diff --git a/CMakeLists.txt b/CMakeLists.txt index 77d547e..9521495 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,6 +179,7 @@ add_library(NintendoSDK OBJECT include/nn/util/util_BytePtr.h include/nn/util/util_IntrusiveList.h include/nn/util/util_BitUtil.h + include/nn/util/util_IntrusiveList.h include/nn/util/util_ResDic.h include/nn/util/util_StringView.h include/nn/ui2d/detail/TexCoordArray.h @@ -205,16 +206,6 @@ add_library(NintendoSDK OBJECT include/nn/nn.h include/nn/settings.h include/nn/hid.h - include/nn/atk/detail/StreamSoundRuntime.h - include/nn/atk/detail/BasicSound.h - include/nn/atk/detail/WaveSoundRuntime.h - include/nn/atk/detail/SequenceSoundRuntime.h - include/nn/atk/detail/SoundArchiveManager.h - include/nn/atk/detail/AdvancedWaveSoundRuntime.h - include/nn/atk/AuxBus.h - include/nn/atk/SoundArchivePlayer.h - include/nn/atk/SoundPlayer.h - include/nn/atk/SoundDataManager.h include/nn/nfp.h include/nn/nfp/nfp.h include/nn/nfp/nfp_types.h @@ -236,6 +227,164 @@ add_library(NintendoSDK OBJECT include/nn/friends.h include/nn/mem.h + include/nn/audio/audio_Adpcm.h + include/nn/audio/audio_AudioRendererTypes.h + include/nn/audio/audio_Common.h + include/nn/audio/audio_EffectTypes.h + include/nn/audio/audio_FinalMixTypes.h + include/nn/audio/audio_MemoryPoolTypes.h + include/nn/audio/audio_PerformanceMetrics.h + include/nn/audio/audio_PerformanceMetricsTypes.h + include/nn/audio/audio_SampleFormat.h + include/nn/audio/audio_SinkTypes.h + include/nn/audio/audio_SubMixTypes.h + include/nn/audio/audio_VoiceTypes.h + include/nn/audio/audio_WaveBuffer.h + + include/nn/atk/atk_Adpcm.h + include/nn/atk/atk_BiquadFilterCallback.h + include/nn/atk/atk_FsSoundArchive.h + include/nn/atk/atk_Global.h + include/nn/atk/atk_SequenceSoundHandle.h + include/nn/atk/atk_SoundActor.h + include/nn/atk/atk_SoundArchive.h + include/nn/atk/atk_SoundArchivePlayer.h + include/nn/atk/atk_SoundDataManager.h + include/nn/atk/atk_SoundHandle.h + include/nn/atk/atk_SoundHeap.h + include/nn/atk/atk_SoundMemoryAllocatable.h + include/nn/atk/atk_SoundPlayer.h + include/nn/atk/atk_SoundStartable.h + include/nn/atk/atk_SoundSystem.h + include/nn/atk/atk_StreamSoundHandle.h + include/nn/atk/atk_WaveSoundHandle.h + include/nn/atk/detail/atk_AddonSoundArchiveContainer.h + include/nn/atk/detail/atk_AdvancedWaveSound.h + include/nn/atk/detail/atk_AdvancedWaveSoundFile.h + include/nn/atk/detail/atk_AdvancedWaveSoundFileReader.h + include/nn/atk/detail/atk_AdvancedWaveSoundPlayer.h + include/nn/atk/detail/atk_AdvancedWaveSoundRuntime.h + include/nn/atk/detail/atk_BasicSound.h + include/nn/atk/detail/atk_BasicSoundPlayer.h + include/nn/atk/detail/atk_BusMixVolumePacket.h + include/nn/atk/detail/atk_Config.h + include/nn/atk/detail/atk_DisposeCallback.h + include/nn/atk/detail/atk_DisposeCallbackManager.h + include/nn/atk/detail/atk_ElementType.h + include/nn/atk/detail/atk_ExternalSoundPlayer.h + include/nn/atk/detail/atk_GroupFile.h + include/nn/atk/detail/atk_GroupFileReader.h + include/nn/atk/detail/atk_IntrusiveList.h + include/nn/atk/detail/atk_IRegionInfoReadable.h + include/nn/atk/detail/atk_IStreamDataDecoder.h + include/nn/atk/detail/atk_ItemType.h + include/nn/atk/detail/atk_LoaderManager.h + include/nn/atk/detail/atk_MoveValue.h + include/nn/atk/detail/atk_NoteOnCallback.h + include/nn/atk/detail/atk_OutputAdditionalParam.h + include/nn/atk/detail/atk_PlayerHeap.h + include/nn/atk/detail/atk_PlayerHeapDataManager.h + include/nn/atk/detail/atk_RegionManager.h + include/nn/atk/detail/atk_SoundArchiveFile.h + include/nn/atk/detail/atk_SoundArchiveFileReader.h + include/nn/atk/detail/atk_SoundArchiveLoader.h + include/nn/atk/detail/atk_SoundArchiveManager.h + include/nn/atk/detail/atk_SoundInstanceManager.h + include/nn/atk/detail/atk_SoundRuntimeUtility.h + include/nn/atk/detail/atk_StartInfoReader.h + include/nn/atk/detail/atk_ValueArray.h + include/nn/atk/detail/atk_VolumeThroughModePacket.h + include/nn/atk/detail/atk_WaveArchiveFile.h + include/nn/atk/detail/atk_WaveArchiveFileReader.h + include/nn/atk/detail/atk_WaveFile.h + include/nn/atk/detail/debug/atk_Debug.h + include/nn/atk/detail/dsp/atk_BiquadFilterPresets.h + include/nn/atk/detail/dsp/atk_DspadpcmReader.h + include/nn/atk/detail/dsp/atk_HardwareManager.h + include/nn/atk/detail/seq/atk_Bank.h + include/nn/atk/detail/seq/atk_BankFile.h + include/nn/atk/detail/seq/atk_BankFileReader.h + include/nn/atk/detail/seq/atk_MmlCommand.h + include/nn/atk/detail/seq/atk_MmlParser.h + include/nn/atk/detail/seq/atk_MmlSequenceTrack.h + include/nn/atk/detail/seq/atk_MmlSequenceTrackAllocator.h + include/nn/atk/detail/seq/atk_SequenceSound.h + include/nn/atk/detail/seq/atk_SequenceSoundFile.h + include/nn/atk/detail/seq/atk_SequenceSoundFileReader.h + include/nn/atk/detail/seq/atk_SequenceSoundPlayer.h + include/nn/atk/detail/seq/atk_SequenceSoundRuntime.h + include/nn/atk/detail/seq/atk_SequenceTrack.h + include/nn/atk/detail/seq/atk_SequenceTrackAllocator.h + include/nn/atk/detail/strm/atk_StreamBufferPool.h + include/nn/atk/detail/strm/atk_StreamSound.h + include/nn/atk/detail/strm/atk_StreamSoundFile.h + include/nn/atk/detail/strm/atk_StreamSoundFileLoader.h + include/nn/atk/detail/strm/atk_StreamSoundFileReader.h + include/nn/atk/detail/strm/atk_StreamSoundLoader.h + include/nn/atk/detail/strm/atk_StreamSoundPlayer.h + include/nn/atk/detail/strm/atk_StreamSoundPrefetchFile.h + include/nn/atk/detail/strm/atk_StreamSoundPrefetchFileReader.h + include/nn/atk/detail/strm/atk_StreamSoundRuntime.h + include/nn/atk/detail/strm/atk_StreamTrack.h + include/nn/atk/detail/thread/atk_Command.h + include/nn/atk/detail/thread/atk_CommandManager.h + include/nn/atk/detail/thread/atk_DriverCommand.h + include/nn/atk/detail/thread/atk_SoundThread.h + include/nn/atk/detail/thread/atk_Task.h + include/nn/atk/detail/thread/atk_TaskManager.h + include/nn/atk/detail/thread/atk_TaskThread.h + include/nn/atk/detail/thread/atk_ThreadInfoReader.h + include/nn/atk/detail/util/atk_CurveAdshr.h + include/nn/atk/detail/util/atk_BinaryFileFormat.h + include/nn/atk/detail/util/atk_BinaryTypes.h + include/nn/atk/detail/util/atk_CurveLfo.h + include/nn/atk/detail/util/atk_FrameHeap.h + include/nn/atk/detail/util/atk_InstancePool.h + include/nn/atk/detail/util/atk_MemoryFileStream.h + include/nn/atk/detail/util/atk_Util.h + include/nn/atk/detail/util/atk_WavBinary.h + include/nn/atk/detail/util/atk_WavOutFileStream.h + include/nn/atk/detail/voice/atk_Channel.h + include/nn/atk/detail/voice/atk_ChannelManager.h + include/nn/atk/detail/voice/atk_LowLevelVoice.h + include/nn/atk/detail/voice/atk_MultiVoice.h + include/nn/atk/detail/voice/atk_MultiVoiceManager.h + include/nn/atk/detail/voice/atk_Voice.h + include/nn/atk/detail/voice/atk_VoiceCommand.h + include/nn/atk/detail/wsd/atk_WaveSound.h + include/nn/atk/detail/wsd/atk_WaveSoundFile.h + include/nn/atk/detail/wsd/atk_WaveSoundFileReader.h + include/nn/atk/detail/wsd/atk_WaveSoundLoader.h + include/nn/atk/detail/wsd/atk_WaveSoundPlayer.h + include/nn/atk/detail/wsd/atk_WaveSoundRuntime.h + include/nn/atk/effect/atk_EffectAux.h + include/nn/atk/effect/atk_EffectBase.h + include/nn/atk/submix/atk_ChannelMixVolume.h + include/nn/atk/submix/atk_FinalMix.h + include/nn/atk/submix/atk_OutputMixer.h + include/nn/atk/submix/atk_OutputReceiver.h + include/nn/atk/submix/atk_SubMix.h + include/nn/atk/util/atk_AudioRendererPerformanceReader.h + include/nn/atk/util/atk_DeviceOutRecorder.h + include/nn/atk/util/atk_ProfileReader.h + include/nn/atk/util/atk_TaskProfileReader.h + include/nn/atk/fnd/basis/atkfnd_Config.h + include/nn/atk/fnd/basis/atkfnd_FrameHeapImpl.h + include/nn/atk/fnd/basis/atkfnd_HeapBase.h + include/nn/atk/fnd/basis/atkfnd_PrimitiveTypes.h + include/nn/atk/fnd/basis/atkfnd_Result.h + include/nn/atk/fnd/basis/atkfnd_RuntimeTypeInfo.h + include/nn/atk/fnd/basis/atkfnd_ScopedLock.h + include/nn/atk/fnd/basis/atkfnd_Time.h + include/nn/atk/fnd/basis/atkfnd_WorkBufferAllocator.h + include/nn/atk/fnd/io/atkfnd_FileStream.h + include/nn/atk/fnd/io/atkfnd_FileStreamImpl.h + include/nn/atk/fnd/io/atkfnd_FileStreamProxy.h + include/nn/atk/fnd/io/atkfnd_Stream.h + include/nn/atk/fnd/io/atkfnd_StreamCache.h + include/nn/atk/fnd/os/atkfnd_CriticalSection.h + include/nn/atk/fnd/os/atkfnd_Thread.h + include/nvn/nvn_Cpp.h include/nvn/nvn_CppFuncPtrBase.h include/nvn/nvn_CppMethods.h diff --git a/include/nn/atk/AuxBus.h b/include/nn/atk/AuxBus.h deleted file mode 100644 index a954c4b..0000000 --- a/include/nn/atk/AuxBus.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -namespace nn { -namespace atk { -enum class AuxBus : s32 { AuxBus_A, AuxBus_B, AuxBus_C }; -} -} // namespace nn diff --git a/include/nn/atk/SoundArchivePlayer.h b/include/nn/atk/SoundArchivePlayer.h deleted file mode 100644 index c364664..0000000 --- a/include/nn/atk/SoundArchivePlayer.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file SoundArchivePlayer.h - * @brief Basic sound player from a sound archive. - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace nn { -namespace atk { -class SoundArchivePlayer { -public: - SoundArchivePlayer(); - - virtual ~SoundArchivePlayer(); - - bool IsAvailable() const; - void Finalize(); - void StopAllSound(s32, bool); - void DisposeInstances(); - - nn::atk::detail::SoundArchiveManager mArchiveManager; // _8 - nn::atk::detail::SequenceSoundRuntime mSeqSoundRuntime; // _50 - nn::atk::detail::WaveSoundRuntime mWaveSoundRuntime; // _130 - nn::atk::detail::AdvancedWaveSoundRuntime mAdvancedWaveSound; // _1B0 - nn::atk::detail::StreamSoundRuntime mStreamSoundRuntime; // _1E0 - u64 _290; - u32 _298; - u8 _29C[0x2E8 - 0x29C]; -}; -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/SoundDataManager.h b/include/nn/atk/SoundDataManager.h deleted file mode 100644 index f9366c6..0000000 --- a/include/nn/atk/SoundDataManager.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file SoundDataManager.h - * @brief Sound data management implementation. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -class SoundDataManager { -public: - SoundDataManager(); - virtual ~SoundDataManager(); - - virtual void InvalidateData(void const*, void const*); - virtual void SetFileAddressToTable(u32, void const*); - virtual u64 GetFileAddressFromTable(u32) const; - virtual u32 GetFileAddressImpl(u32) const; - - u8 _0[0x240]; -}; -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/SoundPlayer.h b/include/nn/atk/SoundPlayer.h deleted file mode 100644 index 3711c77..0000000 --- a/include/nn/atk/SoundPlayer.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file SoundPlayer.h - * @brief Sound player. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -enum PauseMode { - -}; - -class SoundPlayer { -public: - SoundPlayer(); - ~SoundPlayer(); - - void StopAllSound(s32); - void Update(); - void DoFreePlayerHeap(); - void detail_SortPriorityList(bool); - void PauseAllSound(s32, bool); - void PauseAllSound(bool, s32, nn::atk::PauseMode); - void SetVolume(f32 vol); - void SetLowPassFilterFrequency(f32 filterFreq); - void SetBiquadFilter(s32 filterType, f32 baseFreq); - void SetDefaultOutputLine(u32 line); - - void detail_SetPlayableSoundLimit(s32 limit); - bool CanPlaySound(s32); - - u64 _0; - u64 _8; - u64 _10; - u64 _18; - u64 _20; - u64 _28; - u64 _30; - u64 _38; - s32 _40; - s32 mPlayableSoundCount; // _44 - s32 _48; - f32 mVolume; // _4C - f32 mLowPassFreq; // _50 - s32 mFilterType; // _54 - f32 mBaseFreq; // _58 - u32 mDefaultOutputLine; // _5C - f32 mOutputVolume; // _60 - u64 _64; - u64 _6C; -}; -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/atk_Adpcm.h b/include/nn/atk/atk_Adpcm.h new file mode 100644 index 0000000..720973b --- /dev/null +++ b/include/nn/atk/atk_Adpcm.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +using AdpcmParam = audio::AdpcmParameter; + +struct alignas(64) AdpcmContext { + audio::AdpcmContext audioAdpcmContext; +}; +static_assert(sizeof(AdpcmContext) == 0x40); + +struct AdpcmContextNotAligned { + audio::AdpcmContext audioAdpcmContext; +}; +static_assert(sizeof(AdpcmContextNotAligned) == 0x6); + +namespace detail { +void DecodeDspAdpcm(position_t playPosition, AdpcmContext& context, + const AdpcmParam& param, const void* adpcmData, + size_t decodeSamples, s16* dest); +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_BiquadFilterCallback.h b/include/nn/atk/atk_BiquadFilterCallback.h new file mode 100644 index 0000000..1647e9b --- /dev/null +++ b/include/nn/atk/atk_BiquadFilterCallback.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace nn::atk { +class BiquadFilterCallback { +public: + using Coefficients = BiquadFilterCoefficients; + + virtual ~BiquadFilterCallback(); + + virtual void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) = 0; +}; +static_assert(sizeof(BiquadFilterCallback) == 0x8); +} \ No newline at end of file diff --git a/include/nn/atk/atk_FsSoundArchive.h b/include/nn/atk/atk_FsSoundArchive.h new file mode 100644 index 0000000..2ef5a18 --- /dev/null +++ b/include/nn/atk/atk_FsSoundArchive.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include + +namespace nn::atk { +class FsSoundArchive : SoundArchive { +public: + enum FileAccessMode { + FileAccessMode_Always, + FileAccessMode_InFunction + }; + + constexpr static u32 BufferAlignSize = 64; + + FsSoundArchive(); + ~FsSoundArchive() override; + + void Close(); + bool Open(const char* path); + + bool LoadFileHeader(); + + detail::fnd::FileStream* OpenStream(void* buffer, size_t size, + position_t begin, size_t length) const override; + + detail::fnd::FileStream* OpenExtStream(void* buffer, size_t size, const char* extFilePath, + void* cacheBuffer, size_t cacheSize) const override; + + size_t detail_GetRequiredStreamBufferSize() const override; + + bool LoadHeader(void* buffer, size_t size); + bool LoadLabelStringData(void* buffer, size_t size); + + void FileAccessBegin() const override; + void FileAccessEnd() const override; + + void* detail_GetFileAddress(ItemId itemId) override; + +private: + detail::SoundArchiveFileReader m_ArchiveReader; + detail::fnd::FileStreamImpl m_FileStream; + bool m_IsOpened; + u8 m_FileAccessMode; + u8 m_Padding[2]; + u32 m_FileAccessCount; + char m_SoundArchiveFullPath[SoundArchive::FilePathMax]; + detail::fnd::CriticalSection m_FileOpenCloseLock; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(FsSoundArchive) == 0x618); +#else +static_assert(sizeof(FsSoundArchive) == 0x610); +#endif +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_Global.h b/include/nn/atk/atk_Global.h new file mode 100644 index 0000000..3231c66 --- /dev/null +++ b/include/nn/atk/atk_Global.h @@ -0,0 +1,432 @@ +#pragma once + +#include +#include + +namespace nn::atk { +enum WaveType { + WaveType_Invalid = -1, + WaveType_Nwwav, + WaveType_Dspadpcm, +}; + +struct WaveBuffer { + enum Status { + Status_Free, + Status_Wait, + Status_Play, + Status_Done, + }; + + void* bufferAddress; + size_t bufferSize; + size_t sampleLength; + position_t sampleOffset; + AdpcmContext* pAdpcmContext; + void* userParam; + bool loopFlag; + Status status; + WaveBuffer* next; +}; +static_assert(sizeof(WaveBuffer) == 0x40); + +enum AuxBus { + AuxBus_A, + AuxBus_B, + AuxBus_C, + AuxBus_Count, +}; + +enum BiquadFilterType { + BiquadFilterType_Inherit = -1, + BiquadFilterType_Min = -1, + BiquadFilterType_DataMin = 0, + + BiquadFilterType_None = 0, + BiquadFilterType_LowPassFilter, + BiquadFilterType_HighPassFilter, + BiquadFilterType_BandPassFilter512, + BiquadFilterType_BandPassFilter1024, + BiquadFilterType_BandPassFilter2048, + BiquadFilterType_LowPassFilterNw4fCompatible48k, + BiquadFilterType_HighPassFilterNw4fCompatible48k, + BiquadFilterType_BandPassFilter512Nw4fCompatible48k, + BiquadFilterType_BandPassFilter1024Nw4fCompatible48k, + BiquadFilterType_BandPassFilter2048Nw4fCompatible48k, + + BiquadFilterType_UserMin = 0x40, + + BiquadFilterType_User0 = BiquadFilterType_UserMin, + BiquadFilterType_User1, + BiquadFilterType_User2, + BiquadFilterType_User3, + BiquadFilterType_User4, + BiquadFilterType_User5, + BiquadFilterType_User6, + BiquadFilterType_User7, + BiquadFilterType_User8, + BiquadFilterType_User9, + BiquadFilterType_User10, + BiquadFilterType_User11, + BiquadFilterType_User12, + BiquadFilterType_User13, + BiquadFilterType_User14, + BiquadFilterType_User15, + BiquadFilterType_User16, + BiquadFilterType_User17, + BiquadFilterType_User18, + BiquadFilterType_User19, + BiquadFilterType_User20, + BiquadFilterType_User21, + BiquadFilterType_User22, + BiquadFilterType_User23, + BiquadFilterType_User24, + BiquadFilterType_User25, + BiquadFilterType_User26, + BiquadFilterType_User27, + BiquadFilterType_User28, + BiquadFilterType_User29, + BiquadFilterType_User30, + BiquadFilterType_User31, + BiquadFilterType_User32, + BiquadFilterType_User33, + BiquadFilterType_User34, + BiquadFilterType_User35, + BiquadFilterType_User36, + BiquadFilterType_User37, + BiquadFilterType_User38, + BiquadFilterType_User39, + BiquadFilterType_User40, + BiquadFilterType_User41, + BiquadFilterType_User42, + BiquadFilterType_User43, + BiquadFilterType_User44, + BiquadFilterType_User45, + BiquadFilterType_User46, + BiquadFilterType_User47, + BiquadFilterType_User48, + BiquadFilterType_User49, + BiquadFilterType_User50, + BiquadFilterType_User51, + BiquadFilterType_User52, + BiquadFilterType_User53, + BiquadFilterType_User54, + BiquadFilterType_User55, + BiquadFilterType_User56, + BiquadFilterType_User57, + BiquadFilterType_User58, + BiquadFilterType_User59, + BiquadFilterType_User60, + BiquadFilterType_User61, + BiquadFilterType_User62, + BiquadFilterType_User63, + + BiquadFilterType_Max = 0x7f, + BiquadFilterType_UserMax = 0x7f, +}; + +enum ChannelIndex { + ChannelIndex_FrontLeft, + ChannelIndex_FrontRight, + ChannelIndex_RearLeft, + ChannelIndex_RearRight, + ChannelIndex_FrontCenter, + ChannelIndex_Lfe, + ChannelIndex_Count, +}; + +enum CircularBufferSinkState { + CircularBufferSinkState_Invalid, + CircularBufferSinkState_Started, + CircularBufferSinkState_Stopped, +}; + +enum FsPriority { + FsPriority_RealTime, + FsPriority_Normal, + FsPriority_Low, +}; + +struct AdshrCurve { + u8 m_Attack; + u8 m_Decay; + u8 m_Sustain; + u8 m_Hold; + u8 m_Release; +}; +static_assert(sizeof(AdshrCurve) == 0x5); + +static const AdshrCurve DefaultAdshrCurve = {127, 127, 127, 127, 127}; +static const AdshrCurve WsdDefaultAdshrCurve = {127, 127, 127, 127, 127}; + +struct BiquadFilterCoefficients { + s16 b0; + s16 b1; + s16 b2; + s16 a1; + s16 a2; +}; +static_assert(sizeof(BiquadFilterCoefficients) == 0xa); + +struct DspAdpcmParam { + u16 coef[8][2]; + u16 predScale; + u16 yn1; + u16 yn2; +}; +static_assert(sizeof(DspAdpcmParam) == 0x26); + +enum MixMode { + MixMode_Pan = 0, + MixMode_MixVolume = 1, + MixMode_Mixparameter = 1, + MixMode_Count = 2, +}; + +struct MixParameter { + union { + struct { + f32 fL; + f32 fR; + f32 rL; + f32 rR; + f32 fC; + f32 lfe; + }; + float ch[6]; + }; +}; +static_assert(sizeof(MixParameter) == 0x18); + +struct MixVolume { + union { + struct { + f32 frontLeft; + f32 frontRight; + f32 rearLeft; + f32 rearRight; + f32 frontCenter; + f32 lowFrequencyEffect; + }; + float channel[6]; + }; +}; +static_assert(sizeof(MixVolume) == 0x18); + +enum OutputDevice { + OutputDevice_Main, + OutputDevice_Count, +}; + +enum OutputDeviceIndex { + OutputDeviceIndex_Main, + OutputDeviceIndex_Count, +}; + +enum OutputLine { + OutputLine_Main = 1, + OutputLine_ReservedMax = 2, + + OutputLine_User0 = 0x10000, + OutputLine_User1 = 0x20000, + OutputLine_User2 = 0x40000, + OutputLine_User3 = 0x80000, +}; + +enum OutputLineIndex { + OutputLineIndex_Main = 1, + OutputLineIndex_ReservedMax = 2, + + OutputLineIndex_User0 = 0x10000, + OutputLineIndex_User1 = 0x20000, + OutputLineIndex_User2 = 0x40000, + OutputLineIndex_User3 = 0x80000, +}; + +enum OutputMode { + OutputMode_Monaural, + OutputMode_Stereo, + OutputMode_Surround, + OutputMode_Dpl2, + OutputMode_Count, +}; + +struct OutputMix { + f32 channelGain[24]; +}; +static_assert(sizeof(OutputMix) == 0x60); + +enum PanCurve { + PanCurve_Sqrt, + PanCurve_Sqrt0Db, + PanCurve_Sqrt0DbClamp, + PanCurve_Sincos, + PanCurve_Sincos0Db, + PanCurve_Sincos0DbClamp, + PanCurve_Linear, + PanCurve_Linear0Db, + PanCurve_Linear0DbClamp, + PanCurve_Invalid, +}; + +enum PanMode { + PanMode_Dual, + PanMode_Balance, + PanMode_Invalid, +}; + +enum PauseMode { + PauseMode_Default = 0, + + PauseMode_Nw4fSndCompatible = PauseMode_Default, + PauseMode_PauseImmediately, +}; + +enum SampleFormat { + SampleFormat_PcmS8, + SampleFormat_PcmS16, + SampleFormat_DspAdpcm, + SampleFormat_PcmS32, +}; + +enum SampleRateConverterType { + SampleRateConverterType_None, + SampleRateConverterType_Linear, + SampleRateConverterType_4Tap, +}; + +enum SequenceMute { + SequenceMute_Off, + SequenceMute_NoStop, + SequenceMute_Release, + SequenceMute_Stop, +}; + +enum SinglePlayType { + SinglePlayType_None, + SinglePlayType_PrioritizeOldest, + SinglePlayType_PrioritizeOldestEffectiveDuration, + SinglePlayType_PrioritizeOldestWithDuration = SinglePlayType_PrioritizeOldestEffectiveDuration, + + SinglePlayType_PrioritizeNewest, + SinglePlayType_PrioritizeNewestEffectiveDuration, + SinglePlayType_PrioritizeNewestWithDuration = SinglePlayType_PrioritizeNewestEffectiveDuration, +}; + +struct StreamDataInfo {}; + +enum UpdateType { + UpdateType_AudioFrame, + UpdateType_GameFrame, +}; + +enum VolumeThroughModeBitFlag { + VolumeThroughMode_Binary = 1, +}; + +namespace detail { +enum DecodeMode { + DecodeMode_Invalid = -1, + DecodeMode_Default, + DecodeMode_Cpu, + DecodeMode_Accelerator, +}; + +struct DspAdpcmLoopParam { + u16 loopPredScale; + u16 loopYn1; + u16 loopYn2; +}; +static_assert(sizeof(DspAdpcmLoopParam) == 0x6); + +struct OutputBusMixVolume { + float volume[2][24]; +}; +static_assert(sizeof(OutputBusMixVolume) == 0xc0); + +struct OutputParam { + float volume; + u32 mixMode; + MixParameter mixParameter[2]; + float pan; + float span; + float send[4]; +}; +static_assert(sizeof(OutputParam) == 0x50); + +struct SoundInstanceConfig { + bool isBusMixVolumeEnabled; + bool isVolumeThroughModeEnabled; + s32 busCount; +}; +static_assert(sizeof(SoundInstanceConfig) == 8); + +enum StreamFileType { + StreamFileType_Bfstm, + StreamFileType_Opus, +}; + +enum VoiceState { + VoiceState_Play, + VoiceState_Stop, + VoiceState_Pause, +}; + +struct VoiceInfo { + VoiceState voiceState; + WaveBuffer::Status waveBufferStatus; + void* waveBufferTag; + u32 playPosition; + void* userId; +}; +static_assert(sizeof(VoiceInfo) == 0x20); + +class VoiceParam { +public: + VoiceParam(); + + void Initialize(); + +private: + float m_Volume; + float m_Pitch; + OutputMix m_TvMix; + bool m_MonoFilterFlag; + bool m_BiquadFilterFlag; + BiquadFilterCoefficients m_BiquadFilterCoefficients; + u16 m_MonoFilterCutoff; + u8 m_InterpolationType; +}; +static_assert(sizeof(VoiceParam) == 0x78); + +struct WaveInfo { + struct ChannelParam { + void* dataAddress; + s32 dataSize; + DspAdpcmParam adpcmParam; + DspAdpcmLoopParam adpcmLoopParam; + }; + static_assert(sizeof(ChannelParam) == 0x38); + + SampleFormat sampleFormat; + bool loopFlag; + s32 channelCount; + s32 sampleRate; + position_t loopStartFrame; + position_t loopEndFrame; + position_t originalLoopStartFrame; + size_t dataSize; + ChannelParam channelParam[2]; +}; +static_assert(sizeof(WaveInfo) == 0xa0); + +static const OutputMix DefaultTvMix{1.0, 1.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +} // namespace nn::atk::detail + +using SoundFrameUserCallback = void(*)(std::uintptr_t); +using SoundThreadUserCallback = void(*)(std::uintptr_t); +using SoundStopCallback = void(*)(); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SequenceSoundHandle.h b/include/nn/atk/atk_SequenceSoundHandle.h new file mode 100644 index 0000000..bde9626 --- /dev/null +++ b/include/nn/atk/atk_SequenceSoundHandle.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +namespace detail { +class SequenceSound; +} // namespace nn::atk::detail + +class SequenceSoundHandle { +public: + using TrackBitFlagSet = util::BitFlagSet<16, void>; + + constexpr static u32 BankIndexMin = 0; + constexpr static u32 BankIndexMax = 3; + + constexpr static u8 TransposeMin = 192; + constexpr static u8 TransposeMax = 63; + + constexpr static u8 VelocityRangeMin = 0; + constexpr static u8 VelocityRangeMax = 127; + + constexpr static u32 VariableIndexMax = 15; + constexpr static u32 TrackIndexMax = 15; + + explicit SequenceSoundHandle(SoundHandle* pSoundHandle); + + void detail_AttachSoundAsTempHandle(detail::SequenceSound* pSound); + void DetachSound(); + +private: + detail::SequenceSound* m_pSound; +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SoundActor.h b/include/nn/atk/atk_SoundActor.h new file mode 100644 index 0000000..8700089 --- /dev/null +++ b/include/nn/atk/atk_SoundActor.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace nn::atk { +class SoundActor { +public: + using ActorPlayer = detail::ExternalSoundPlayer; +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SoundArchive.h b/include/nn/atk/atk_SoundArchive.h new file mode 100644 index 0000000..222d938 --- /dev/null +++ b/include/nn/atk/atk_SoundArchive.h @@ -0,0 +1,271 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk { +namespace detail{ +class SoundArchiveFileReader; +struct SoundArchiveParametersHook; +struct SoundArchiveFilesHook; +} // namespace nn::atk::detail + +class SoundArchive { +public: + using ItemId = u32; + using FileId = ItemId; + using StringId = ItemId; + + constexpr static ItemId InvalidId = -1; + + constexpr static u32 UserParamIndexMax = 3; + constexpr static u32 ResultInvalidSoundId = 0; + constexpr static u32 InvalidUserParam = -1; + constexpr static u32 SequenceBankMax = 4; + constexpr static u32 StreamTrackCount = 8; + + constexpr static s32 FilePathMax = 639; + + enum SoundType { + SoundType_Invalid, + SoundType_Sequence, + SoundType_Stream, + SoundType_Wave, + SoundType_AdvancedWave, + }; + + enum DecodeMode { + DecodeMode_Default, + DecodeMode_Cpu, + DecodeMode_Accelerator, + }; + + struct SoundInfo { + FileId fileId; + ItemId playerId; + u8 actorPlayerId; + u8 playerPriority; + u8 volume; + u8 remoteFilter; + PanMode panMode; + PanCurve panCurve; + SinglePlayType singlePlayType; + u16 singlePlayEffectiveDuration; + bool isFrontBypass; + }; + static_assert(sizeof(SoundInfo) == 0x1c); + + struct BankInfo { + FileId fileId; + }; + static_assert(sizeof(BankInfo) == 0x4); + + struct PlayerInfo { + s32 playableSoundMax; + u32 playerHeapSize; + }; + static_assert(sizeof(PlayerInfo) == 0x8); + + struct SoundGroupInfo { + ItemId startId; + ItemId endId; + detail::Util::Table fileIdTable; + }; + static_assert(sizeof(SoundGroupInfo) == 0x10); + + struct GroupInfo { + FileId fileId; + u32 groupFileSize; + }; + static_assert(sizeof(GroupInfo) == 0x8); + + struct FileInfo { + constexpr static u32 InvalidOffset = -1; + constexpr static u32 InvalidSize = -1; + + u32 fileSize; + u32 offsetFromFileBlockHead; + char* externalFilePath; + }; + static_assert(sizeof(FileInfo) == 0x10); + + struct WaveArchiveInfo { + u32 fileId; + u32 waveCount; + bool isLoadIndividual; + u8 padding[3]; + }; + static_assert(sizeof(WaveArchiveInfo) == 0xc); + + struct SoundArchivePlayerInfo { + s32 sequenceSoundCount; + s32 sequenceTrackCount; + s32 streamSoundCount; + s32 streamTrackCount; + s32 streamChannelCount; + s32 waveSoundCount; + s32 waveTrackCount; + s32 streamBufferTimes; + bool isAdvancedWaveSoundEnabled; + }; + static_assert(sizeof(SoundArchivePlayerInfo) == 0x24); + + struct SequenceSoundInfo { + u32 startOffset; + u32 bankIds[4]; + u32 allocateTrackFlags; + u8 channelPriority; + bool isReleasePriorityFix; + }; + static_assert(sizeof(SequenceSoundInfo) == 0x1c); + + enum StreamFileType { + StreamFileType_Invalid = 0, + StreamFileType_NwStreamBinary = 1, + StreamFileType_Opus = 3, + }; + + struct StreamTrackInfo { + u8 volume; + u8 pan; + u8 surroundPan; + u8 flags; + u8 mainSend; + u8 fxSend[3]; + u8 lowPassFilterFrequency; + u8 biquadType; + u8 biquadValue; + u8 channelCount; + s8 globalChannelIndex[2]; + }; + static_assert(sizeof(StreamTrackInfo) == 0xe); + + struct StreamSoundInfo { + void Setup(); + + u16 allocateTrackFlags; + u16 allocateChannelCount; + f32 pitch; + u8 mainSend; + u8 fxSend[3]; + StreamTrackInfo trackInfo[8]; + StreamFileType streamFileType; + DecodeMode decodeMode; + FileId prefetchFileId; + void* streamBufferPool; + }; + static_assert(sizeof(StreamSoundInfo) == 0x90); + + struct StreamSoundInfo2 { + bool isLoop; + u32 loopStartFrame; + u32 loopEndFrame; + }; + static_assert(sizeof(StreamSoundInfo2) == 0xc); + + struct WaveSoundInfo { + u32 index; + u32 allocateTrackCount; + u8 channelPriority; + bool isReleasePriorityFix; + }; + static_assert(sizeof(WaveSoundInfo) == 0xc); + + struct AdvancedWaveSoundInfo { + u32 waveArchiveId; + }; + static_assert(sizeof(AdvancedWaveSoundInfo) == 0x4); + + struct Sound3DInfo { + u32 flags; + f32 decayRatio; + u8 decayCurve; + u8 dopplerFactor; + }; + static_assert(sizeof(Sound3DInfo) == 0xc); + + SoundArchive(); + + virtual ~SoundArchive(); + + bool IsAvailable() const; + + void Initialize(detail::SoundArchiveFileReader* reader); + void Finalize(); + + s32 GetSoundCount() const; + s32 GetPlayerCount() const; + s32 GetSoundGroupCount() const; + s32 GetGroupCount() const; + s32 GetBankCount() const; + s32 GetWaveArchiveCount() const; + + s32 detail_GetFileCount() const; + + char* GetItemLabel(ItemId id) const; + FileId GetItemFileId(ItemId id) const; + FileId GetItemPrefetchFileId(ItemId id) const; + + void* GetSoundUserParam(u32) const; + + bool ReadSoundUserParam(u32*, u32, s32) const; + + u32 GetSoundType(u32) const; + + bool ReadSoundInfo(SoundInfo* info, u32) const; + bool ReadSequenceSoundInfo(SequenceSoundInfo* info, u32) const; + bool ReadStreamSoundInfo(StreamSoundInfo* info, u32) const; + + bool detail_ReadStreamSoundInfo2(u32, StreamSoundInfo2*) const; + bool detail_ReadWaveSoundInfo(u32, WaveSoundInfo*) const; + bool detail_ReadAdvancedWaveSoundInfo(u32, AdvancedWaveSoundInfo*) const; + + bool ReadPlayerInfo(PlayerInfo*, u32) const; + bool ReadSoundArchivePlayerInfo(SoundArchivePlayerInfo*) const; + bool ReadSound3DInfo(Sound3DInfo*, u32) const; + bool ReadBankInfo(BankInfo*, u32) const; + bool ReadWaveArchiveInfo(u32, WaveArchiveInfo*) const; + + bool detail_ReadSoundGroupInfo(u32, SoundGroupInfo*) const; + + bool ReadGroupInfo(GroupInfo*, u32) const; + + bool detail_ReadFileInfo(u32, FileInfo*) const; + + detail::Util::Table* detail_GetWaveArchiveIdTable(ItemId id); + + bool detail_OpenFileStream(FileId id, void*, size_t, void*, size_t) const; + + void OpenExtStreamImpl(void*, size_t, const char*, void*, size_t) const; + + char* detail_GetExternalFileFullPath(const char*, char*, size_t) const; + + void SetExternalFileRoot(const char*); + + bool ReadStreamSoundFilePath(char*, size_t, u32); + + void* detail_GetAttachedGroupTable(u32) const; + + virtual void* detail_GetFileAddress(ItemId itemId) = 0; + virtual size_t detail_GetRequiredStreamBufferSize() const = 0; + + virtual void FileAccessBegin() const; + virtual void FileAccessEnd() const; + + virtual bool IsAddon(); + + virtual detail::fnd::FileStream* OpenStream(void* buffer, size_t size, + position_t begin, size_t length) const = 0; + + virtual detail::fnd::FileStream* OpenExtStream(void* buffer, size_t size, const char* extFilePath, + void* cacheBuffer, size_t cacheSize) const = 0; + +private: + detail::SoundArchiveFileReader* m_pFileReader{}; + detail::SoundArchiveParametersHook* m_pParametersHook{}; + char m_ExtFileRoot[FilePathMax]; + u32 m_FileBlockOffset; +}; +static_assert(sizeof(SoundArchive) == 0x2a0); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/atk_SoundArchivePlayer.h b/include/nn/atk/atk_SoundArchivePlayer.h new file mode 100644 index 0000000..cfed52a --- /dev/null +++ b/include/nn/atk/atk_SoundArchivePlayer.h @@ -0,0 +1,216 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace nn::atk { +class SoundArchivePlayer : SoundStartable { +public: + constexpr static u32 BufferAlignSize = 4096; + constexpr static u32 StreamBufferTimesMax = 4; + constexpr static u8 UserParamBoundary = 4; + + struct InitializeParam { + SoundArchive* pSoundArchive; + SoundDataManager* pSoundDataManager; + void* pSetupBuffer; + size_t setupBufferSize; + void* pStreamBuffer; + size_t streamBufferSize; + void* pStreamCacheBuffer; + size_t streamCacheSize; + bool enablePreparingStreamInstanceBufferFromSetupBuffer; + void* pStreamInstanceBuffer; + size_t streamInstanceBufferSize; + size_t userParamSizePerSound; + s32 addonSoundArchiveCount; + }; + static_assert(sizeof(InitializeParam) == 0x68); + + struct StreamSoundInstanceState { + s32 activeStreamSoundInstanceCount; + s32 activeStreamChannelCount; + s32 activeStreamTrackCount; + }; + static_assert(sizeof(StreamSoundInstanceState) == 0xc); + + SoundArchivePlayer(); + ~SoundArchivePlayer() override; + + bool IsAvailable() const; + + bool Initialize(const SoundArchive* arc, const SoundDataManager* manager, void* buffer, + size_t size, void* strmBuffer, size_t strmBufferSize, + size_t userParamSizePerSound); + bool Initialize(const InitializeParam& param); + + void Finalize(); + + void StopAllSound(s32, bool); + + void DisposeInstances(); + + static size_t GetRequiredMemSize(const SoundArchive* arc); + static size_t GetRequiredMemSize(const SoundArchive* arc, size_t userParamSizePerSound, + s32 addonSoundArchiveCount); + static size_t GetRequiredMemSize(const SoundArchive* arc, size_t userParamSizePerSound); + static size_t GetRequiredMemSize(const InitializeParam& param); + + static size_t GetRequiredStreamInstanceSize(const SoundArchive* arc); + + size_t GetRequiredStreamBufferSize(const SoundArchive* arc) const; + size_t GetRequiredStreamBufferTimes(const SoundArchive* arc) const; + + static size_t GetRequiredStreamCacheSize(const SoundArchive* arc, size_t); + + + bool SetupMram(const SoundArchive* pArc, void* buffer, size_t size, + size_t userParamSizePerSound, s32 addonSoundArchiveCount, + void* streamSoundInstanceBuffer, size_t streamSoundInstanceBufferSize); + + bool SetupSoundPlayer(const SoundArchive* pArc, void** pOutAllocatedAddr, const void* endAddr); + bool SetupAddonSoundArchiveContainer(s32 containerCount, void** pOutAllocatedAddr, const void* endAddr); + bool SetupUserParamForBasicSound(const SoundArchive::SoundArchivePlayerInfo& playerInfo, + void** pOutAllocatedAddr, const void* endAddr, size_t); + + detail::PlayerHeap* CreatePlayerHeap(void** pOutAllocatedAddr, const void* endAddr, size_t); + + void Update(); + + SoundPlayer* GetSoundPlayer(u32); + + SoundArchive* GetSoundArchive() const; + AddonSoundArchive* GetAddonSoundArchive(const char*) const; + AddonSoundArchive* GetAddonSoundArchive(s32) const; + char* GetAddonSoundArchiveName(s32) const; + os::Tick* GetAddonSoundArchiveAddTick(s32) const; + SoundDataManager* GetAddonSoundDataManager(const char*) const; + + SoundPlayer* GetSoundPlayer(u32) const; + SoundPlayer* GetSoundPlayer(const char*); + SoundPlayer* GetSoundPlayer(const char*) const; + + void* detail_GetFileAddress(SoundArchive::FileId fileId) const; + + void AddAddonSoundArchive(const char*, const AddonSoundArchive*, const SoundDataManager*); + void RemoveAddonSoundArchive(const AddonSoundArchive*); + +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void SetDefaultOutputReceiver(OutputReceiver* pOutputReceiver); +#endif + + StartResult detail_SetupSound(SoundHandle* handle, u32 soundId, bool holdFlag, + const char* soundArchiveName, const StartInfo* startInfo) override; + StartResult detail_SetupSoundImpl(SoundHandle* handle, u32 soundId, + detail::BasicSound::AmbientInfo* ambientArgInfo, + SoundActor* actor, bool holdFlag, const char* soundArchiveName, + const StartInfo* startInfo); + + bool IsSoundArchiveFileHooksEnabled() const; + + void LockSoundArchiveFileHooks(); + + bool IsSequenceSoundEdited(const char*) const; + bool IsStreamSoundEdited(const char*) const; + bool IsWaveSoundEdited(const char*) const; + + void EnableHook(const SoundArchive*, bool); + + StartResult PreprocessSinglePlay(const SoundArchive::SoundInfo& info, u32 soundId, + SoundPlayer& player); + + void SetCommonSoundParam(detail::BasicSound* pSound, const SoundArchive::SoundInfo* info); + + void UnlockSoundArchiveFileHooks(); + + void SetSequenceUserProcCallback(SequenceUserProcCallback callback, void* arg); + + static void SetSequenceSkipIntervalTick(s32 tick); + static s32 GetSequenceSkipIntervalTick(); + + Result ReadWaveSoundDataInfo(detail::WaveSoundDataInfo*, u32, const SoundArchive*, + const SoundDataManager*) const; + Result ReadWaveSoundDataInfo(detail::WaveSoundDataInfo*, u32, const char*) const; + Result ReadWaveSoundDataInfo(detail::WaveSoundDataInfo*, const char*, const char*) const; + Result ReadWaveSoundDataInfo(detail::WaveSoundDataInfo*, u32) const; + Result ReadWaveSoundDataInfo(detail::WaveSoundDataInfo*, const char*) const; + + Result ReadStreamSoundDataInfo(detail::StreamSoundDataInfo*, const SoundArchive*, u32) const; + Result ReadStreamSoundDataInfo(detail::StreamSoundDataInfo*, u32, const char*) const; + Result ReadStreamSoundDataInfo(detail::StreamSoundDataInfo*, const char*, const char*) const; + Result ReadStreamSoundDataInfo(detail::StreamSoundDataInfo*, u32) const; + Result ReadStreamSoundDataInfo(detail::StreamSoundDataInfo*, const char*) const; + + static size_t GetRequiredWorkBufferSizeToReadStreamSoundHeader(); + + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, u32, + const char* const*, s32, const SoundArchive*, + void*, size_t) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, u32, const char*, + void*, size_t) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, u32, + const char* const*, s32, void*, size_t, + const char*) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, const char*, + const char*, void*, size_t) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, const char*, + const char* const*, s32, void*, size_t, + const char*) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, u32, + const char* const*, s32, void*, size_t) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, const char*, + const char* const*, s32, void*, size_t) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, const char*, + const char*, void*, size_t, + const char* soundArchiveName) const; + Result ReadStreamSoundRegionDataInfo(detail::StreamSoundRegionDataInfo*, u32, const char*, + void*, size_t, const char* soundArchiveName) const; + + void DumpMemory() const; + + bool ReadStreamSoundInstanceState(StreamSoundInstanceState*) const; + + Result CheckStreamSoundFileExisting(u32) const; + Result CheckStreamSoundFileExisting(u32, const char* soundArchiveName) const; + Result CheckStreamSoundFileExisting(char* streamSoundName) const; + Result CheckStreamSoundFileExisting(const char*, const char*) const; + Result CheckStreamSoundFileExisting(const SoundArchive*, u32) const; + + SoundArchive::ItemId detail_GetItemId(char* pString) override; + SoundArchive::ItemId detail_GetItemId(char* pString, const char* soundArchiveName) override; + +private: + detail::SoundArchiveManager m_SoundArchiveManager; + u32 m_SoundPlayerCount; + SoundPlayer* m_pSoundPlayers; + detail::SequenceSoundRuntime m_SequenceSoundRuntime; + detail::WaveSoundRuntime m_WaveSoundRuntime; + detail::AdvancedWaveSoundRuntime m_AdvancedWaveSoundRuntime; + detail::StreamSoundRuntime m_StreamSoundRuntime; + size_t m_SoundUserParamSize; + s32 m_ArchiveContainerCount; + detail::AddonSoundArchiveContainer* m_pArchiveContainers; + os::Tick m_AddonSoundArchiveLastAddTick; + audio::MemoryPoolType m_MemoryPoolForStreamInstance; + bool m_IsMemoryPoolForStreamInstanceAttached; + audio::MemoryPoolType m_MemoryPoolForPlayerHeap; + bool m_IsMemoryPoolForPlayerHeapAttached; + detail::SoundArchiveFilesHook* m_pSoundArchiveFilesHook; + bool m_IsEnableWarningPrint; + bool m_IsInitialized; + bool m_IsAdvancedWaveSoundEnabled; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* m_pDefaultOutputReceiver; + u8 m_Padding[1]; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SoundArchivePlayer) == 0x2e0); +#else +static_assert(sizeof(SoundArchivePlayer) == 0x310); +#endif +} // namespace nn::atk diff --git a/include/nn/atk/atk_SoundDataManager.h b/include/nn/atk/atk_SoundDataManager.h new file mode 100644 index 0000000..1a086af --- /dev/null +++ b/include/nn/atk/atk_SoundDataManager.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk { + +namespace detail { +class SoundFileManager; +} // namespace nn::atk::detail + +class SoundDataManager : detail::driver::DisposeCallback, detail::SoundArchiveLoader { +public: + struct FileAddress { + void* address; + }; + + using FileTable = detail::Util::Table; + + constexpr static u32 BufferAlignSize = 8; + + SoundDataManager(); + ~SoundDataManager() override; + + size_t GetRequiredMemSize(const SoundArchive* arc) const; + + bool Initialize(const SoundArchive* pArchive, void* buffer, size_t size); + + bool CreateTables(void**, const SoundArchive* pArchive, void*); + + void Finalize(); + + void InvalidateData(const void* start, const void* end) override; + + void* detail_GetFileAddress(SoundArchive::FileId fileId) const; + void* GetFileAddressImpl(SoundArchive::FileId fileId) const override; + + void* SetFileAddressToTable(SoundArchive::FileId fileId, const void* address) override; + void* GetFileAddressFromTable(SoundArchive::FileId fileId) const override; + + void* SetFileAddress(SoundArchive::FileId fileId, const void* address); + + SoundArchive::FileId detail_GetFileIdFromTable(const void*) const; + + bool SetFileAddressInGroupFile(const void*, size_t); + void ClearFileAddressInGroupFile(const void*, size_t); + + void InvalidateSoundData(const void*, size_t); + +private: + FileTable* m_pFileTable; + detail::SoundFileManager* m_pFileManager; +}; +static_assert(sizeof(SoundDataManager) == 0x240); +} // namespace nn::atk diff --git a/include/nn/atk/atk_SoundHandle.h b/include/nn/atk/atk_SoundHandle.h new file mode 100644 index 0000000..3aac003 --- /dev/null +++ b/include/nn/atk/atk_SoundHandle.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace nn::atk { +class SoundHandle { +public: + enum MuteState { + MuteState_Normal, + MuteState_Muting, + MuteState_Muted, + MuteState_Unmuting, + MuteState_Invalid, + }; + + enum PauseState { + PauseState_Normal, + PauseState_Pausing, + PauseState_Paused, + PauseState_Unpausing, + PauseState_Invalid + }; + + ~SoundHandle() = default; + + void detail_DuplicateHandle(SoundHandle* other); + + void DetachSound(); + + void detail_AttachSoundAsTempHandle(detail::BasicSound* sound); + void detail_AttachSound(detail::BasicSound* sound); + + void CalculateSoundParamCalculationValues(SoundParamCalculationValues* calcValues) const; + +private: + detail::BasicSound* m_pSound; +}; +static_assert(sizeof(SoundHandle) == 0x8); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SoundHeap.h b/include/nn/atk/atk_SoundHeap.h new file mode 100644 index 0000000..11c9858 --- /dev/null +++ b/include/nn/atk/atk_SoundHeap.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace nn::atk::detail { +class SoundHeap : SoundMemoryAllocatable { +public: + SoundHeap(); + ~SoundHeap() override; + + void Destroy(); + + bool Create(void* startAddress, size_t size); + bool Create(void* startAddress, size_t size, bool); + + void Clear(); + + void* Allocate(size_t size) override; + + static void DisposeCallbackFunc(void* mem, size_t size, void* arg); + + void* Allocate(size_t size, + SoundMemoryAllocatable::DisposeCallback heapCallback, + void* heapCallbackArg) override; + + size_t GetAllocateSize(size_t size, bool needMemoryPool) override; + + s32 SaveState(); + void LoadState(s32 state); + +private: + fnd::CriticalSection m_CriticalSection; + FrameHeap m_FrameHeap; + audio::MemoryPoolType m_MemoryPool; + bool m_IsAutoMemoryPoolManagementEnabled; +}; +static_assert(sizeof(SoundHeap) == 0x50); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/atk_SoundMemoryAllocatable.h b/include/nn/atk/atk_SoundMemoryAllocatable.h new file mode 100644 index 0000000..eb2a56d --- /dev/null +++ b/include/nn/atk/atk_SoundMemoryAllocatable.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace nn::atk { +class SoundMemoryAllocatable { +public: + using DisposeCallback = void(*)(void*); + + virtual ~SoundMemoryAllocatable() = 0; + virtual void* Allocate(size_t size) = 0; + virtual void* Allocate(size_t size, DisposeCallback callback, void* callbackArg) = 0; + virtual size_t GetAllocateSize(size_t size, bool needMemoryPool) = 0; +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SoundPlayer.h b/include/nn/atk/atk_SoundPlayer.h new file mode 100644 index 0000000..113065b --- /dev/null +++ b/include/nn/atk/atk_SoundPlayer.h @@ -0,0 +1,107 @@ +#pragma once + +#include + +#include +#include +#include + +namespace nn::atk { +class SoundPlayer { +public: + using SoundList = util::IntrusiveList< + detail::BasicSound, util::IntrusiveListMemberNodeTraits< + detail::BasicSound, &detail::BasicSound::m_SoundPlayerPlayLink>>; + using PriorityList = util::IntrusiveList< + detail::BasicSound, util::IntrusiveListMemberNodeTraits< + detail::BasicSound, &detail::BasicSound::m_SoundPlayerPriorityLink>>; + using PlayerHeapList = util::IntrusiveList< + detail::PlayerHeap, util::IntrusiveListMemberNodeTraits< + detail::PlayerHeap, &detail::PlayerHeap::m_Link>>; + struct OutputParam { + f32 volume; + f32 mainSend; + f32 fxSend[3]; + }; + static_assert(sizeof(OutputParam) == 0x14); + + SoundPlayer(); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + explicit SoundPlayer(detail::OutputAdditionalParam* pParam); +#endif + ~SoundPlayer(); + + void StopAllSound(s32 fadeFrames); + + void Update(); + + void DoFreePlayerHeap(); + + void detail_SortPriorityList(bool reverse); + + void PauseAllSound(s32, bool); + void PauseAllSound(bool, s32); + void PauseAllSound(bool, s32, PauseMode); + + void SetVolume(f32 volume); + void SetLowPassFilterFrequency(f32 lpfFreq); + void SetBiquadFilter(s32 biquadFilterType, f32 biquadFilterValue); + void SetDefaultOutputLine(u32 line); + + void SetMainSend(f32 send); + f32 GetMainSend() const; + + void SetEffectSend(AuxBus bus, f32 send); + void GetEffectSend(AuxBus bus) const; + + void SetSend(s32 subMixBus, f32 send); + f32 GetSend(s32 subMixBus); + + void SetOutputVolume(OutputDevice device, f32 volume); + + void RemoveSoundList(detail::BasicSound* pSound); + + void InsertPriorityList(detail::BasicSound* pSound); + void RemovePriorityList(detail::BasicSound* pSound); + + void detail_SortPriorityList(detail::BasicSound* pSound); + + bool detail_AppendSound(detail::BasicSound* pSound); + bool detail_RemoveSound(detail::BasicSound* pSound); + + void SetPlayableSoundCount(s32 count); + + void detail_SetPlayableSoundLimit(s32 limit); + + bool detail_CanPlaySound(s32 startPriority); + bool CanPlaySound(s32 startPriority); + + void detail_AppendPlayerHeap(detail::PlayerHeap* pHeap); + detail::PlayerHeap* detail_AllocPlayerHeap(); + void detail_FreePlayerHeap(detail::PlayerHeap* pHeap); + +private: + SoundList m_SoundList; + PriorityList m_PriorityList; + PlayerHeapList m_PlayerHeapFreeList; + PlayerHeapList m_PlayerHeapFreeReqList; + s32 m_PlayableCount; + s32 m_PlayableLimit; + u32 m_PlayerHeapCount; + f32 m_Volume; + f32 m_LpfFreq; + s32 m_BiquadType; + f32 m_BiquadValue; + u32 m_OutputLineFlag; + OutputParam m_TvParam; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + detail::OutputAdditionalParam* m_pOutputAdditionalParam; +#endif + bool m_IsFirstComeBased; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SoundPlayer) == 0x78); +#else +static_assert(sizeof(SoundPlayer) == 0x88); +#endif +} // namespace nn::atk diff --git a/include/nn/atk/atk_SoundStartable.h b/include/nn/atk/atk_SoundStartable.h new file mode 100644 index 0000000..e9fa361 --- /dev/null +++ b/include/nn/atk/atk_SoundStartable.h @@ -0,0 +1,162 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nn::atk { +class SoundStartable { +public: + struct StartInfo { + enum StartOffsetType { + StartOffsetType_MilliSeconds, + StartOffsetType_Tick, + StartOffsetType_Sample, + }; + + enum EnableFlagBit { + EnableFlagBit_StartOffset = 1 << 0, + EnableFlagBit_PlayerId = 1 << 1, + EnableFlagBit_PlayerPriority = 1 << 2, + EnableFlagBit_ActorPlayerId = 1 << 3, + EnableFlagBit_SequenceSoundInfo = 1 << 4, + EnableFlagBit_StreamSoundInfo = 1 << 5, + EnableFlagBit_WaveSoundInfo = 1 << 6, + EnableFlagBit_VoiceRendererType = 1 << 7, + EnableFlagBit_FadeFrame = 1 << 8, + EnableFlagBit_SoundStopCallback = 1 << 9, + EnableFlagBit_StreamSoundMetaInfo = 1 << 10, + EnableFlagBit_StreamSoundMetaInfo2 = 1 << 11, + EnableFlagBit_DelayTime = 1 << 12, + EnableFlagBit_DelayCount = 1 << 13, + EnableFlagBit_UpdateType = 1 << 14, + EnableFlagBit_SubMixIndex = 1 << 15, + EnableFlagBit_OutputReceiver = 1 << 16, + }; + + struct SequenceSoundInfo { + void* sequenceDataAddress; + char* startLocationLabel; + SoundArchive::ItemId bankIds[4]; + }; + static_assert(sizeof(SequenceSoundInfo) == 0x20); + + struct StreamSoundInfo { + char* externalPath; + void* pExternalData; + size_t externalDataSize; + StreamRegionCallback regionCallback; + void* regionCallbackArg; + void* prefetchData; + bool forcePlayPrefetchFlag; + detail::driver::StreamBufferPool* pStreamBufferPool; + }; + static_assert(sizeof(StreamSoundInfo) == 0x40); + + struct WaveSoundInfo { + enum EnableParameterFlagBit { + EnableParameterFlagBit_Release = 1, + EnableParameterFlagBit_ContextCalculationSkipMode, + }; + + void* waveAddress; + s8 waveType; + u8 m_Padding[3]; + s32 enableParameterFlag; + s32 release; + bool isContextCalculationSkipMode; + }; + static_assert(sizeof(WaveSoundInfo) == 0x18); + + u32 enableFlag; + StartOffsetType startOffsetType; + s32 startOffset; + SoundArchive::ItemId playerId; + s32 playerPriority; + s32 actorPlayerId; + SequenceSoundInfo sequenceSoundInfo; + StreamSoundInfo streamSoundInfo; + SoundArchive::StreamSoundInfo streamSoundMetaInfo; + SoundArchive::StreamSoundInfo2 streamSoundMetaInfo2; + WaveSoundInfo waveSoundInfo; + u8 voiceRendererType; + s32 fadeFrame; + SoundStopCallback soundStopCallback; + s32 delayTime; + s32 delayCount; + UpdateType updateType; + s32 subMixIndex; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pOutputReceiver; +#endif + }; + + struct StartResult { + enum ResultCode { + ResultCode_Success, + ResultCode_ErrorLowPriority, + ResultCode_ErrorInvalidLabelString, + ResultCode_ErrorInvalidSoundId, + ResultCode_CanceledBySinglePlay, + ResultCode_ErrorCanceledForPrioritizingOldest = ResultCode_CanceledBySinglePlay, + ResultCode_ErrorNotDataLoaded, + ResultCode_ErrorNotSequenceLoaded, + ResultCode_ErrorNotBankLoaded, + ResultCode_ErrorNotWsdLoaded, + ResultCode_ErrorNotWarcLoaded, + ResultCode_ErrorNotEnoughPlayerHeap, + ResultCode_ErrorCannotOpenFile, + ResultCode_ErrorNotAvailable, + ResultCode_ErrorCannotAllocateTrack, + ResultCode_ErrorNotEnoughInstance, + ResultCode_ErrorInvalidParameter, + ResultCode_ErrorInvalidSequenceStartLocationLabel, + ResultCode_ErrorActorNotInitialized, + ResultCode_ErrorInvalidWarcId, + ResultCode_ErrorInvalidBankData, + ResultCode_ErrorInvalidStreamFileId, + ResultCode_ErrorInvalidStreamFilePath, + + ResultCode_ErrorUser = 0x80, + ResultCode_ErrorUnknown = 0xff, + }; + + ResultCode m_Code; + }; + + virtual ~SoundStartable() = 0; + + virtual StartResult detail_SetupSound(SoundHandle* handle, u32 soundId, + bool holdFlag, const char* soundArchiveName, + const StartInfo* startInfo) = 0; + + virtual SoundArchive::ItemId detail_GetItemId(char* pString) = 0; + virtual SoundArchive::ItemId detail_GetItemId(char* pString, const char* soundArchiveName) = 0; + + StartResult StartSound(SoundHandle* handle, u32 soundId, + const char* soundArchiveName, const StartInfo* startInfo); + StartResult StartSound(SoundHandle* handle, u32 soundId, const StartInfo* startInfo); + StartResult StartSound(SoundHandle* handle, const char* pString, + const char* soundArchiveName, const StartInfo* startInfo); + StartResult StartSound(SoundHandle* handle, const char* soundArchiveName, + const StartInfo* startInfo); + + StartResult HoldSound(SoundHandle* handle, u32 soundId, const char* soundArchiveName, + const StartInfo* startInfo); + StartResult HoldSound(SoundHandle* handle, u32 soundId, const StartInfo* startInfo); + StartResult HoldSound(SoundHandle* handle, const char* pString, const StartInfo* startInfo); + StartResult HoldSound(SoundHandle* handle, const char* pString, const char* soundArchiveName, + const StartInfo* startInfo); + + StartResult PrepareSound(SoundHandle* handle, u32 soundId, const char* soundArchiveName, + const StartInfo* startInfo); + StartResult PrepareSound(SoundHandle* handle, u32 soundId, const StartInfo* startInfo); + StartResult PrepareSound(SoundHandle* handle, const char* pString, + const char* soundArchiveName, const StartInfo* startInfo); + StartResult PrepareSound(SoundHandle* handle, const char* soundArchiveName, + const StartInfo* startInfo); +}; +static_assert(sizeof(SoundStartable) == 0x8); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_SoundSystem.h b/include/nn/atk/atk_SoundSystem.h new file mode 100644 index 0000000..f86d0ad --- /dev/null +++ b/include/nn/atk/atk_SoundSystem.h @@ -0,0 +1,297 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace nn::atk { +struct SoundSystem { + static bool g_IsInitialized; + static bool g_IsStreamLoadWait; + static bool g_IsEnterSleep; + static bool g_IsInitializedDriverCommandManager; + + static uintptr_t g_LoadThreadStackPtr; + static size_t g_LoadThreadStackSize; + + static uintptr_t g_SoundThreadStackPtr; + static size_t g_SoundThreadStackSize; + + static uintptr_t g_PerformanceFrameBuffer; + static size_t g_PerformanceFrameBufferSize; + + static size_t g_SoundThreadCommandBufferSize; + static size_t g_TaskThreadCommandBufferSize; + static size_t g_VoiceCommandBufferSize; + + static uintptr_t g_MemoryPoolForSoundSystem; + + static s32 g_RendererSampleRate; + static s32 g_CustomSubMixSubMixCount; + static s32 g_CustomSubMixMixBufferCount; + + static bool g_IsProfilerEnabled; + static bool g_IsDetailSoundThreadProfilerEnabled; + static bool g_IsAdditionalEffectBusEnabled; + static bool g_IsAdditionalSubMixEnabled; + static bool g_IsEffectEnabled; + static bool g_IsRecordingEnabled; + static bool g_IsCircularBufferSinkEnabled; + static bool g_IsCircularBufferSinkWarningDisplayed; + static bool g_IsVoiceDropEnabled; + static bool g_IsPreviousSdkVersionLowPassFilterCompatible; + static bool g_IsUnusedEffectChannelMutingEnabled; + static bool g_IsUserThreadRenderingEnabled; + static bool g_IsCustomSubMixEnabled; + static bool g_IsMemoryPoolAttachCheckEnabled; + static bool g_IsBusMixVolumeEnabled; + static bool g_IsVolumeThroughModeEnabled; + + constexpr static u32 VoiceCountMax = 96; + constexpr static u32 WorkMemoryAlignSize = 4; + constexpr static u32 VoiceCommandManagerCountMax = 2; + constexpr static u32 SoundThreadIntervalUsec = 5000; + + constexpr static s32 g_TaskThreadFsPriority = 1; + constexpr static bool g_IsStreamOpenFailureHalt = true; + constexpr static bool g_IsTaskThreadEnabled = true; + constexpr static bool g_IsManagingMemoryPool = true; + constexpr static u32 g_UserEffectCount = 10; + constexpr static bool g_IsSubMixEnabled = true; + constexpr static bool g_IsPresetSubMixEnabled = true; + constexpr static bool g_IsStereoModeEnabled = true; + constexpr static bool g_IsSoundThreadEnabled = true; + constexpr static s32 g_BusCountMax = 4; + + struct SoundSystemParam { + constexpr static u32 DefaultSoundThreadPriority = 0; + constexpr static u32 DefaultTaskThreadPriority = 0; + constexpr static u32 DefaultSoundThreadStackSize = 0x4000; + constexpr static u32 DefaultTaskThreadStackSize = 0x4000; + constexpr static u32 DefaultSoundThreadCommandBufferSize = 0x20000; + constexpr static u32 DefaultTaskThreadCommandBufferSize = 0x2000; + constexpr static u32 DefaultUserEffectCount = 10; + constexpr static u32 DefaultVoiceCountMax = 96; + constexpr static u32 DefaultSoundThreadCoreNumber = 0; + constexpr static u32 DefaultTaskThreadCoreNumber = 0; + constexpr static u32 DefaultRecordingAudioFrameCount = 8; + + SoundSystemParam(); + + s32 soundThreadPriority{4}; + size_t soundThreadStackSize{0x4000}; + size_t soundThreadCommandBufferSize{0x20000}; + size_t voiceCommandBufferSize; + s32 taskThreadPriority{3}; + size_t taskThreadStackSize{0x4000}; + size_t taskThreadCommandBufferSize{0x2000}; + FsPriority taskThreadFsPriority{FsPriority_Normal}; + bool enableNwRenderer{}; + u32 nwVoiceSynthesizeBufferCount; + s32 rendererSampleRate{48000}; + s32 effectCount{10}; + s32 voiceCountMax{96}; + s32 voiceCommandWaveBufferPacketCount{0x200}; + bool enableProfiler{false}; + bool enableDetailSoundThreadProfile{false}; + bool enableRecordingFinalOutputs{false}; + bool enableCircularBufferSink{false}; + s32 recordingAudioFrameCount{8}; + s32 soundThreadCoreNumber; + s32 taskThreadCoreNumber; + bool enableAdditionalEffectBus{false}; + bool enableAdditionalSubMix{false}; + bool enableTaskThread{true}; + bool enableSoundThread{true}; + bool enableMemoryPoolManagement{true}; + bool enableCircularBufferSinkBufferManagement{true}; + bool enableEffect{true}; + bool enableSubMix{true}; + bool enableStereoMode{false}; + bool enableVoiceDrop{true}; + bool enableCompatibleDownMixSetting{false}; + bool enableCompatibleLowPassFilter; + bool enableUnusedEffectChannelMuting; + bool enableCompatibleBusVolume; + bool enableUserThreadRendering; + bool enableCustomSubMix; + s32 subMixCount{0}; + s32 subMixTotalChannelCount{0}; + s32 mixBufferCount{-1}; + s32 busCountMax{4}; + bool enableMemoryPoolAttachCheck{false}; + bool enableBusMixVolume{false}; + bool enableVolumeThroughMode{false}; + }; + static_assert(sizeof(SoundSystemParam) == 0x88); + + struct InitializeBufferSet { + uintptr_t workMem; + size_t workMemSize; + uintptr_t memoryPoolMem; + size_t memoryPoolMemSize; + uintptr_t circularBufferSinkMem; + size_t circularBufferSinkMemSize; + }; + static_assert(sizeof(InitializeBufferSet) == 0x30); + + static size_t GetRequiredMemSize(const SoundSystemParam& param); + static size_t GetRequiredMemSizeForCircularBufferSink(const SoundSystemParam& param); + static size_t GetRequiredMemSizeForMemoryPool(const SoundSystemParam& param); + + static void SetupHardwareManagerParameter(detail::driver::HardwareManager::HardwareManagerParameter* pOutValue, + SoundSystemParam* parameter); + + static bool detail_InitializeSoundSystem(Result* pOutResult, const SoundSystemParam& param, const InitializeBufferSet& bufferSet); + static void detail_InitializeDriverCommandManager(const SoundSystemParam& param, u64, u64, u64, u64); + + static bool Initialize(SoundSystemParam* param, uintptr_t workMem, size_t workMemSize); + static bool Initialize(Result* pOutResult, const SoundSystemParam& param, + uintptr_t workMem, size_t workMemSize); + + static void SetupInitializeBufferSet(InitializeBufferSet* pOutValue, + SoundSystemParam* param, InitializeBufferSet* bufferSet); + + static bool Initialize(SoundSystemParam* param, uintptr_t workMem, size_t workMemSize, + uintptr_t memoryPoolMem, size_t memoryPoolMemSize); + static bool Initialize(Result* pOutResult, const SoundSystemParam& param, uintptr_t workMem, + size_t workMemSize, uintptr_t memoryPoolMem, size_t memoryPoolMemSize); + + static bool Initialize(const SoundSystemParam& param, const InitializeBufferSet& bufferSet); + static bool Initialize(Result* pOutResult, const SoundSystemParam& param, const InitializeBufferSet& bufferSet); + + static void Finalize(); + + static void SetSoundThreadBeginUserCallback(void(*threadBeginUserCallback)(u64), uintptr_t threadBeginUserCallbackArg); + static void ClearSoundThreadBeginUserCallback(); + + static void SetSoundThreadEndUserCallback(void(*threadEndUserCallback)(u64), uintptr_t threadEndUserCallbackArg); + static void ClearSoundThreadEndUserCallback(); + + static bool IsInitialized(); + + static void SuspendAudioRenderer(TimeSpan timeSpan); + static void ResumeAudioRenderer(TimeSpan timeSpan); + + static void ExecuteRendering(); + + static void AttachMemoryPool(audio::MemoryPoolType* pMemoryPool, void* address, size_t size); + static void DetachMemoryPool(audio::MemoryPoolType* pMemoryPool); + + static void DumpMemory(); + + static size_t GetAudioRendererBufferSize(); + + static void SetupHardwareManagerParameterFromCurrentSetting(detail::driver::HardwareManager::HardwareManagerParameter* pHardwareManagerParameter); + + static size_t GetRecorderBufferSize(); + static size_t GetUserCircularBufferSinkBufferSize(); + static size_t GetLowLevelVoiceAllocatorBufferSize(); + static size_t GetMultiVoiceManagerBufferSize(); + static size_t GetChannelManagerBufferSize(); + static size_t GetDriverCommandBufferSize(); + static size_t GetAllocatableDriverCommandSize(); + static size_t GetAllocatedDriverCommandBufferSize(); + static size_t GetAllocatedDriverCommandCount(); + + static void RegisterAudioRendererPerformanceReader(AudioRendererPerformanceReader& audioRendererPerformanceReader); + + static bool AppendEffect(AuxBus auxBus, EffectBase* pEffectBase, + void* buffer, size_t bufferSize); + static bool AppendEffect(AuxBus auxBus, EffectBase* pEffectBase, + void* buffer, size_t bufferSize, OutputDevice device); + static bool AppendEffect(AuxBus auxBus, EffectBase* pEffectBase, + void* buffer, size_t bufferSize, OutputDevice device, s32 subMixNumber); + + static bool AppendEffect(AuxBus auxBus, EffectAux* pEffectAux, + void* buffer, size_t bufferSize); + static bool AppendEffect(AuxBus auxBus, EffectAux* pEffectAux, + void* buffer, size_t bufferSize, OutputDevice device); + static bool AppendEffect(AuxBus auxBus, EffectAux* pEffectAux, + void* buffer, size_t bufferSize, OutputDevice device, s32 subMixNumber); + + static bool AppendEffectToFinalMix(EffectAux* pEffectAux, void* buffer, size_t bufferSize); + static bool AppendEffectToAdditionalSubMix(EffectAux* pEffectAux, void* buffer, size_t bufferSize); + + static size_t GetRequiredEffectAuxBufferSize(const EffectAux* pEffectAux); + + static void RemoveEffect(AuxBus auxBus, EffectBase* pEffectBase); + static void RemoveEffect(AuxBus auxBus, EffectBase* pEffectBase, OutputDevice outputDevice); + static void RemoveEffect(AuxBus auxBus, EffectBase* pEffectBase, OutputDevice outputDevice, + s32 subMixNumber); + + static void RemoveEffect(AuxBus auxBus, EffectAux* pEffectAux); + static void RemoveEffect(AuxBus auxBus, EffectAux* pEffectAux, OutputDevice outputDevice); + static void RemoveEffect(AuxBus auxBus, EffectAux* pEffectAux, OutputDevice outputDevice, + s32 subMixNumber); + + static void RemoveEffectFromFinalMix(EffectAux* pEffectAux); + static void RemoveEffectFromAdditionalSubMix(EffectAux* pEffectAux); + + static void ClearEffect(AuxBus auxBus); + static void ClearEffect(AuxBus auxBus, OutputDevice outputDevice); + static void ClearEffect(AuxBus auxBus, OutputDevice outputDevice, s32 subMixNumber); + + static void ClearEffectFromFinalMix(); + static void ClearEffectFromAdditionalSubMix(); + + static bool IsClearEffectFinished(AuxBus auxBus); + static bool IsClearEffectFinished(AuxBus auxBus, OutputDevice outputDevice); + static bool IsClearEffectFinished(AuxBus auxBus, OutputDevice outputDevice, s32 subMixNumber); + + static bool IsClearEffectFromFinalMixFinished(); + static bool IsClearEffectFromAdditionalSubMixFinished(); + + static void SetAuxBusVolume(AuxBus auxBus, f32 volume, TimeSpan timeSpan); + static void SetAuxBusVolume(AuxBus auxBus, f32 volume, TimeSpan timeSpan, s32); + + static f32 GetAuxBusVolume(AuxBus auxBus); + static f32 GetAuxBusVolume(AuxBus auxBus, s32 subMixIndex); + + static void SetMainBusChannelVolumeForAdditionalEffect(f32 volume, s32 srcChannel, s32 dstChannel); + static f32 GetMainBusChannelVolumeForAdditionalEffect(s32 srcChannel, s32 dstChannel); + + static void SetAuxBusChannelVolumeForAdditionalEffect(AuxBus auxBus, f32 volume, s32 srcChannel, s32 dstChannel); + static f32 GetAuxBusChannelVolumeForAdditionalEffect(AuxBus auxBus, s32 srcChannel, s32 dstChannel); + + static void SetAllAuxBusChannelVolumeForAdditionalEffect(f32 volume, s32 srcChannel, s32 dstChannel); + static void SetAllBusChannelVolumeForAdditionalEffect(f32 volume, s32 srcChannel, s32 dstChannel); + + static void VoiceCommandProcess(UpdateType updateType, u32); + static void VoiceCommandProcess(u32); + + static void VoiceCommandUpdate(); + + static size_t GetPerformanceFrameBufferSize(); + + static s32 GetDroppedLowLevelVoiceCount(); + + static void RegisterSoundThreadUpdateProfileReader(AtkProfileReader&); + static void UnregisterSoundThreadUpdateProfileReader(AtkProfileReader&); + + static void RegisterSoundThreadInfoRecorder(detail::ThreadInfoRecorder&); + static void UnregisterSoundThreadInfoRecorder(detail::ThreadInfoRecorder&); + + static bool ReadCircularBufferSink(void* buffer, size_t bufferSize); + + static size_t GetCircularBufferSinkBufferSize(); + + static u32 GetRendererSampleCount(); + static u32 GetRendererChannelCountMax(); + + static void StopCircularBufferSink(); + static void StartCircularBufferSink(); + + static CircularBufferSinkState GetCircularBufferSinkState(); + static detail::SoundInstanceConfig GetSoundInstanceConfig(); +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_StreamSoundHandle.h b/include/nn/atk/atk_StreamSoundHandle.h new file mode 100644 index 0000000..6f7fe0a --- /dev/null +++ b/include/nn/atk/atk_StreamSoundHandle.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +namespace detail { +class StreamSound; +} // namespace nn::atk::detail + +class StreamSoundHandle { +public: + using TrackBitFlagSet = util::BitFlagSet<8, void>; + + explicit StreamSoundHandle(SoundHandle* pSoundHandle); + + void detail_AttachSoundAsTempHandle(detail::StreamSound* pSound); + void DetachSound(); + +private: + detail::StreamSound* m_pSound; +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/atk_WaveSoundHandle.h b/include/nn/atk/atk_WaveSoundHandle.h new file mode 100644 index 0000000..2d221b3 --- /dev/null +++ b/include/nn/atk/atk_WaveSoundHandle.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +namespace detail { +class WaveSound; +} // namespace nn::atk::detail + +class WaveSoundHandle { +public: + using TrackBitFlagSet = util::BitFlagSet<8, void>; + + explicit WaveSoundHandle(SoundHandle* pSoundHandle); + + void detail_AttachSoundAsTempHandle(detail::WaveSound* pSound); + + void ForceStop(); + + void DetachSound(); + +private: + detail::WaveSound* m_pSound; +}; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/AdvancedWaveSoundRuntime.h b/include/nn/atk/detail/AdvancedWaveSoundRuntime.h deleted file mode 100644 index 9807b84..0000000 --- a/include/nn/atk/detail/AdvancedWaveSoundRuntime.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file AdvancedWaveSoundRuntime.h - * @brief Runtime wave sound api. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -namespace detail { -class AdvancedWaveSoundRuntime { -public: - AdvancedWaveSoundRuntime(); - ~AdvancedWaveSoundRuntime(); - - void Initialize(s32, void**, void const*); - void Finalize(); - s32 GetActiveCount() const; - void SetupUserParam(void**, u64); - void Update(); - - u8 _0[0x30]; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/BasicSound.h b/include/nn/atk/detail/BasicSound.h deleted file mode 100644 index eb19647..0000000 --- a/include/nn/atk/detail/BasicSound.h +++ /dev/null @@ -1,137 +0,0 @@ -/** - * @file BasicSound.h - * @brief A basic sound. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -class SoundActor; -class SoundPlayer; - -enum MixMode { - -}; - -namespace detail { -class PlayerHeap; -class ExternalSoundPlayer; - -class BasicSound { -public: - BasicSound(); - virtual ~BasicSound(); - - virtual void Initialize(); - virtual void Finalize(); - virtual bool IsPrepared() const = 0; - virtual bool IsAttachedTempSpecialHandle() = 0; - virtual void DetachTempSpecialHandle() = 0; - virtual void OnUpdatePlayerPriority(); - virtual void UpdateMoveValue(); - virtual void OnUpdateParam(); - - void SetPriority(s32, s32); - void GetPriority(s32*, s32*) const; - void ClearIsFinalizedForCannotAllocatedResourceFlag(); - void SetId(u32 newID); - bool IsAttachedGeneralHandle(); - void DetachGeneralHandle(); - bool IsAttachedTempGeneralHandle(); - void DetachTempGeneralHandle(); - void StartPrepared(); - void Stop(s32); - void SetPlayerPriority(s32); - void ForceStop(); - void Pause(bool, s32); - void Mute(bool, s32); - void SetAutoStopCounter(s32); - void FadeIn(s32); - bool IsPause() const; - bool IsMute() const; - void Update(); - void UpdateParam(); - void CalculateVolume() const; - f32 CalculatePitch() const; - f32 CalculateLpfFrequency() const; - u32 CalculateOutLineFlag() const; - void CalculateBiquadFilter(s32*, f32*) const; - void AttachPlayerHeap(nn::atk::detail::PlayerHeap*); - void DetachPlayerHeap(nn::atk::detail::PlayerHeap*); - void AttachSoundPlayer(nn::atk::SoundPlayer*); - void DetachSoundPlayer(nn::atk::SoundPlayer*); - void AttachSoundActor(nn::atk::SoundActor*); - void DetachSoundActor(nn::atk::SoundActor*); - void AttachExternalSoundPlayer(nn::atk::detail::ExternalSoundPlayer*); - void DetachExternalSoundPlayer(nn::atk::detail::ExternalSoundPlayer*); - u32 GetRemainingFadeFrames() const; - u32 GetRemainingPauseFadeFrames() const; - u32 GetRemainingMuteFadeFrames() const; - void SetInitialVolume(f32 vol); - f32 GetInitialVolume() const; - void SetVolume(f32, s32); - s32 GetVolume() const; - void SetPitch(f32); - f32 GetPitch() const; - void SetLpfFreq(f32); - f32 GetLpfFreq() const; - void SetBiquadFilter(s32, f32); - void GetBiquadFilter(s32*, f32*) const; - void SetOutputLine(u32); - u32 GetOutputLine() const; - void ResetOutputLine(); - void SetMixMode(nn::atk::MixMode); - nn::atk::MixMode GetMixMode(); - void SetPan(f32); - f32 GetPan() const; - void SetSurroundPan(f32); - f32 GetSurroundPan() const; - void SetMainSend(f32); - f32 GetMainSend() const; - - u64* _8; // nn::atk::detail::PlayerHeap* - u64* _10; // nn::atk::SoundHandle* - u64* _18; // nn::atk::SoundHandle* - nn::atk::SoundPlayer* mSoundPlayer; // _20 - u64* _28; // nn::atk::SoundActor* - u64* _30; // nn::atk::detail::ExternalSoundPlayer* - u64* _38; // nn::atk::SoundArchive* - u8 _40[0xF0 - 0x40]; - s32 mPriority; // _F0 - u32 _F4; - u32 _F8; - s32 mAutoStopCounter; // _FC - u64 _100; - u32 mID; // _108 - u32 _10C; - u32 _110; - u32 _114; - f32 mInitialVolume; // _118 - f32 mPitch; // _11C - f32 mLpfFreq; // _120 - f32 _124; - u32 mOutputLine; // _128 - f32 _12C; - f32 mVolume; // _130 - u32 _134; - u32 _138; - nn::atk::MixMode mMixMode; // _13C - f32 mPan; // _140 - f32 mSurroundPan; // _144 - f32 mMainSend; // _148 - u8 _14C[0x158 - 0x14C]; - f32 mOutputVol; // _158 - u8 _15C[0x190 - 0x15C]; - f32 mOutputPan; // _190 - f32 mOutputSurroundPan; // _194 - f32 mOutputMainSend; // _198 - f32 mOutputFxSend; // _19C - - static u64 g_LastInstanceId; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/SequenceSoundRuntime.h b/include/nn/atk/detail/SequenceSoundRuntime.h deleted file mode 100644 index 5401a5f..0000000 --- a/include/nn/atk/detail/SequenceSoundRuntime.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file SequenceSoundRuntime.h - * @brief Sequenced Sound Runtime Info - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -namespace detail { -class SoundArchiveManager; - -class SequenceSoundRuntime { -public: - SequenceSoundRuntime(); - ~SequenceSoundRuntime(); - - void Initialize(s32, void**, void const*); - void Finalize(); - void SetupSequenceTrack(s32, void**, void const*); - void SetupUserParam(void**, u64); - bool IsSoundArchiveAvailable() const; - s32 GetActiveCount() const; - s32 GetFreeCount() const; - void SetSequenceSkipIntervalTick(s32 tick); - s32 GetSequenceSkipIntervalTick(); - void Update(); - - u8 _0[0xD0]; - nn::atk::detail::SoundArchiveManager* mArchiveManager; // _D0 - u64 _D8; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/SoundArchiveManager.h b/include/nn/atk/detail/SoundArchiveManager.h deleted file mode 100644 index e96b93e..0000000 --- a/include/nn/atk/detail/SoundArchiveManager.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file SoundArchiveManager.h - * @brief Sound archive manager implementation. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -class SoundHandle; -class SoundArchive; -class SoundDataManager; - -namespace detail { -class AddonSoundArchiveContainer; - -class SoundArchiveManager { -public: - SoundArchiveManager(); - - virtual ~SoundArchiveManager(); - - void Initialize(nn::atk::SoundArchive const*, nn::atk::SoundDataManager const*); - void ChangeTargetArchive(char const*); - void Finalize(); - bool IsAvailable() const; - nn::atk::detail::AddonSoundArchiveContainer* GetAddonSoundArchive(char const*) const; - - u64 _8; - u64* _10; - nn::atk::detail::AddonSoundArchiveContainer* _18; - u64* _20; - nn::atk::SoundArchive* mSoundArchive; // _28 - u64 _30; - u64 _38; - u64 _40; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/StreamSoundRuntime.h b/include/nn/atk/detail/StreamSoundRuntime.h deleted file mode 100644 index 16863f4..0000000 --- a/include/nn/atk/detail/StreamSoundRuntime.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file StreamSoundRuntime.h - * @brief Stream sound runtime information. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -namespace detail { -class StreamSoundRuntime { -public: - StreamSoundRuntime(); - ~StreamSoundRuntime(); - - u8 _0[0xB0]; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/WaveSoundRuntime.h b/include/nn/atk/detail/WaveSoundRuntime.h deleted file mode 100644 index c956da8..0000000 --- a/include/nn/atk/detail/WaveSoundRuntime.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file WaveSoundRuntime.h - * @brief Wave sound runtime info. - */ - -#pragma once - -#include - -namespace nn { -namespace atk { -namespace detail { -class WaveSoundRuntime { -public: - WaveSoundRuntime(); - ~WaveSoundRuntime(); - - void Initialize(s32, void**, void const*); - void Finalize(); - s32 GetActiveCount() const; - s32 GetFreeWaveSoundCount() const; - void SetupUserParam(void**, u64); - void Update(); - - u8 _0[0x80]; -}; -} // namespace detail -} // namespace atk -} // namespace nn diff --git a/include/nn/atk/detail/atk_AddonSoundArchiveContainer.h b/include/nn/atk/detail/atk_AddonSoundArchiveContainer.h new file mode 100644 index 0000000..cf2453b --- /dev/null +++ b/include/nn/atk/detail/atk_AddonSoundArchiveContainer.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nn::atk { +class AddonSoundArchive; + +namespace detail { +class AddonSoundArchiveContainer { +public: + constexpr static s32 SoundArchiveNameCountMax = 64; + + AddonSoundArchiveContainer(); + ~AddonSoundArchiveContainer(); + + bool Initialize(const char* name, + const AddonSoundArchive* pAddonSoundArchive, + const SoundDataManager* pSoundDataManager); + + void Finalize(); + + bool IsSameName(const char* name) const; + + void SetAddTick(const os::Tick& addTick); + + util::IntrusiveListNode m_ElementLink; + +private: + bool m_IsActive; + u8 m_Padding[3]; + SoundArchive* m_pSoundArchive; + SoundDataManager* m_pSoundDataManager; + char m_SoundArchiveName[SoundArchiveNameCountMax]; + os::Tick m_AddTick; +}; +static_assert(sizeof(AddonSoundArchiveContainer) == 0x70); +} // namespace nn::atk::detail +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/atk_AdvancedWaveSound.h b/include/nn/atk/detail/atk_AdvancedWaveSound.h new file mode 100644 index 0000000..52b02af --- /dev/null +++ b/include/nn/atk/detail/atk_AdvancedWaveSound.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class AdvancedWaveSound; +class AdvancedWaveSoundHandle; + +using AdvancedWaveSoundInstanceManager = SoundInstanceManager; + +class AdvancedWaveSound : BasicSound { +public: + explicit AdvancedWaveSound(const AdvancedWaveSoundInstanceManager& manager); + ~AdvancedWaveSound() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void Prepare(const driver::AdvancedWaveSoundPlayer::PrepareParameter& parameter); + + void OnUpdatePlayerPriority() override; + + bool IsAttachedTempSpecialHandle() override; + void DetachTempSpecialHandle() override; + + bool IsPrepared() const override; + + driver::BasicSoundPlayer* GetBasicSoundPlayerHandle() override; + +private: + friend AdvancedWaveSoundInstanceManager; + + util::IntrusiveListNode m_PriorityLink; + AdvancedWaveSoundHandle* m_pTempSpecialHandle; + AdvancedWaveSoundInstanceManager* m_InstanceManager; + driver::AdvancedWaveSoundPlayer m_PlayerInstance; + bool m_IsInitialized; + u8 m_Padding[3]; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(AdvancedWaveSound) == 0x980); +#else +static_assert(sizeof(AdvancedWaveSound) == 0x9b0); +#endif +} // namespace nn::atk::detail diff --git a/include/nn/atk/detail/atk_AdvancedWaveSoundFile.h b/include/nn/atk/detail/atk_AdvancedWaveSoundFile.h new file mode 100644 index 0000000..e5c7d87 --- /dev/null +++ b/include/nn/atk/detail/atk_AdvancedWaveSoundFile.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail { +struct AdvancedWaveSoundFile { + struct WaveSoundTrack; + struct InfoBlockBody { + + BinaryTypes::ReferenceTable* GetTrackReferenceTable() const; + WaveSoundTrack* GetWaveSoundTrack(s32 index) const; + + u32 offsetToTrackTableReference; + BinaryTypes::Reference toTrackTable; + }; + static_assert(sizeof(InfoBlockBody) == 0x8); + + struct InfoBlock { + util::BinaryBlockHeader blockHeader; + InfoBlockBody body; + }; + static_assert(sizeof(InfoBlock) == 0x18); + + struct WaveSoundClip; + struct WaveSoundTrack { + + BinaryTypes::ReferenceTable* GetClipReferenceTable() const; + WaveSoundClip* GetWaveSoundClip(s32 index) const; + + u32 offsetToCurveTableReference; + u32 offsetToClipTableReference; + BinaryTypes::Reference toClipTable; + }; + + struct WaveSoundClip { + u32 waveIndex; + u32 position; + u32 duration; + u32 startOffset; + float pitch; + u8 volume; + u8 pan; + u8 padding[2]; + }; + static_assert(sizeof(WaveSoundClip) == 0x18); + + InfoBlock* GetBlock() const; + + util::BinaryFileHeader fileHeader; +}; +static_assert(sizeof(AdvancedWaveSoundFile) == 0x20); + +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_AdvancedWaveSoundFileReader.h b/include/nn/atk/detail/atk_AdvancedWaveSoundFileReader.h new file mode 100644 index 0000000..2d546c5 --- /dev/null +++ b/include/nn/atk/detail/atk_AdvancedWaveSoundFileReader.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct AdvancedWaveSoundClipInfo { + u32 waveIndex; + u32 position; + u32 duration; + u32 startOffset; + f32 pitch; + u8 volume; + u8 pan; +}; +static_assert(sizeof(AdvancedWaveSoundClipInfo) == 0x18); + +struct AdvancedWaveSoundTrackInfo { + constexpr static u32 AdvancedWaveSoundClipInfoCountMax = 10; + + s32 waveSoundClipCount; + AdvancedWaveSoundClipInfo waveSoundClipInfo[AdvancedWaveSoundClipInfoCountMax]; +}; +static_assert(sizeof(AdvancedWaveSoundTrackInfo) == 0xf4); + +struct AdvancedWaveSoundTrackInfoSet { + constexpr static u32 AdvancedWaveSoundTrackInfoCountMax = 4; + + s32 waveSoundTrackCount; + AdvancedWaveSoundTrackInfo waveSoundTrackInfo[AdvancedWaveSoundTrackInfoCountMax]; +}; +static_assert(sizeof(AdvancedWaveSoundTrackInfoSet) == 0x3d4); + +class AdvancedWaveSoundFileReader { +public: + explicit AdvancedWaveSoundFileReader(const void* pFile); + + s32 GetWaveSoundTrackCount(); + s32 GetWaveSoundClipCount(s32 index); + + bool ReadWaveSoundTrackInfoSet(AdvancedWaveSoundTrackInfoSet* pTrackInfoSet); + +private: + AdvancedWaveSoundFile::InfoBlockBody* m_pInfoBlockBody; +}; +static_assert(sizeof(AdvancedWaveSoundFileReader) == 0x8); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_AdvancedWaveSoundPlayer.h b/include/nn/atk/detail/atk_AdvancedWaveSoundPlayer.h new file mode 100644 index 0000000..368baf5 --- /dev/null +++ b/include/nn/atk/detail/atk_AdvancedWaveSoundPlayer.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nn::atk::detail::driver { +class AdvancedWaveSoundPlayer : BasicSoundPlayer, SoundThread::PlayerCallback { +public: + struct ClipParam { + bool isPlayed; + Channel* pChannel; + }; + static_assert(sizeof(ClipParam) == 0x10); + + struct TrackParam { + constexpr static u32 ClipParamCountMax = 10; + + bool isPlayed; + ClipParam clipParam[ClipParamCountMax]; + }; + static_assert(sizeof(TrackParam) == 0xa8); + + struct TrackParamSet { + constexpr static u32 TrackParamCountMax = 4; + + bool isPlayed; + TrackParam trackParam[TrackParamCountMax]; + }; + static_assert(sizeof(TrackParamSet) == 0x2a8); + + struct PrepareParameter { + SoundArchive::AdvancedWaveSoundInfo advancedWaveSoundInfo; + UpdateType updateType; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + s32 subMixIndex; +#endif + void* pAwsdFile; + void* pWarcFile; + }; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + static_assert(sizeof(PrepareParameter) == 0x20); +#else + static_assert(sizeof(PrepareParameter) == 0x18); +#endif + + AdvancedWaveSoundPlayer(); + ~AdvancedWaveSoundPlayer() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void TearDownPlayer(); + void ReleaseTracks(); + + void Start() override; + void Stop() override; + void Pause(bool isPauseEnabled) override; + + void Prepare(const PrepareParameter& parameter); + + void SetupPlayer(); + bool SetupTracks(); + + void Update(); + bool UpdateTracks(); + + void InitializeTrackParams(); + + bool StartClip(ClipParam* pClipParam, + SoundArchive::AdvancedWaveSoundInfo* pWaveSoundClipInfo); + bool UpdateClip(ClipParam* pClipParam, + SoundArchive::AdvancedWaveSoundInfo* pWaveSoundClipInfo); + void ReleaseClip(ClipParam* pClipParam); + void StopClip(ClipParam* pClipParam); + + void OnUpdateFrameSoundThread() override; + void OnUpdateFrameSoundThreadWithAudioFrameFrequency() override; + void OnShutdownSoundThread() override; + +private: + SoundArchive::AdvancedWaveSoundInfo m_AdvancedWaveSoundInfo; + AdvancedWaveSoundTrackInfoSet m_AdvancedWaveSoundTrackInfoSet; + TrackParamSet m_TrackParamSet; + void* m_pAwsdFile; + void* m_pWarcFile; + UpdateType m_UpdateType; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + s32 m_SubMixIndex; +#endif + u32 m_CurrentTime; + bool m_IsPrepared; + bool m_IsInitialized; + bool m_IsRegisterPlayerCallback; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(AdvancedWaveSoundPlayer) == 0x768); +#else +static_assert(sizeof(AdvancedWaveSoundPlayer) == 0x778); +#endif +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/atk_AdvancedWaveSoundRuntime.h b/include/nn/atk/detail/atk_AdvancedWaveSoundRuntime.h new file mode 100644 index 0000000..dbc9ed4 --- /dev/null +++ b/include/nn/atk/detail/atk_AdvancedWaveSoundRuntime.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace nn::atk::detail { +class AdvancedWaveSoundRuntime { +public: + AdvancedWaveSoundRuntime(); + ~AdvancedWaveSoundRuntime(); + + bool Initialize(s32 soundCount, void** pOutAllocatedAddr, const void* endAddr); + void Finalize(); + + static size_t GetRequiredMemorySize(const SoundArchive::SoundArchivePlayerInfo& soundArchivePlayerInfo, + size_t alignmentSize); + + s32 GetActiveCount() const; + s32 GetFreeAdvancedWaveSoundCount() const; + + void SetupUserParam(void** startAddr, size_t adjustSize); + + void Update(); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + AdvancedWaveSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, + s32 ambientPriority, BasicSound::AmbientInfo* ambientArgInfo); +#else + AdvancedWaveSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, + s32 ambientPriority, BasicSound::AmbientInfo* ambientArgInfo, + OutputReceiver* pOutputReceiver); +#endif + + SoundStartable::StartResult PrepareImpl(const SoundArchive* pSoundArchive, + const SoundDataManager* pSoundDataManager, + SoundArchive::ItemId soundId, + AdvancedWaveSound* sound, + const SoundArchive::SoundInfo* commonInfo, + const StartInfoReader& startInfoReader); + + void DumpMemory(const SoundArchive*) const; + +private: + AdvancedWaveSoundInstanceManager m_InstanceManager; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(AdvancedWaveSoundRuntime) == 0x30); +#else +static_assert(sizeof(AdvancedWaveSoundRuntime) == 0x38); +#endif +} // namespace nn::atk::detail diff --git a/include/nn/atk/detail/atk_BasicSound.h b/include/nn/atk/detail/atk_BasicSound.h new file mode 100644 index 0000000..d234db4 --- /dev/null +++ b/include/nn/atk/detail/atk_BasicSound.h @@ -0,0 +1,450 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace nn::atk { +class SoundActor; +class SoundPlayer; +class SoundHandle; + +class OutputAmbientParam { +private: + f32 m_Volume; + f32 m_Pan; + f32 m_SurroundPan; + f32 m_FxSend[3]; +}; +static_assert(sizeof(OutputAmbientParam) == 0x18); + +class SoundAmbientParam { +public: + constexpr static u32 OutputLineFlagInherit = -1; + +private: + f32 m_Volume; + f32 m_Pitch; + f32 m_Lpf; + f32 m_BiquadFilterValue; + s32 m_BiquadFilterType; + s32 m_Priority; + u32 m_UserData; + s32 m_OutputLineFlag; + OutputAmbientParam m_TvParam; +}; +static_assert(sizeof(SoundAmbientParam) == 0x38); + +class SoundParam { +private: + f32 m_Volume; + f32 m_Pitch; + f32 m_Lpf; + f32 m_BiquadFilterValue; + s32 m_BiquadFilterType; + s32 m_Priority; + s32 m_OutputLineFlag; + u32 m_UserData; + OutputAmbientParam m_TvParam; +}; +static_assert(sizeof(SoundParam) == 0x38); + +struct SoundParamCalculationValues { + struct SoundArchiveParam { + f32 volume; + }; + static_assert(sizeof(SoundArchiveParam) == 0x4); + + struct SoundPlayerParam { + f32 volume; + f32 lpf; + s32 bqfType; + f32 bqfValue; + f32 outputVolume[1]; + f32 outputMainSend[1]; + f32 outputEffectSend[1][3]; + }; + + struct Sound3DParam { + f32 volume; + f32 pitch; + f32 lpf; + s32 bqfType; + f32 bqfValue; + u32 outputLineFlag; + f32 outputVolume[1]; + f32 outputPan[1]; + f32 outputSurroundPan[1]; + f32 outputEffectSend[1][3]; + s32 playerPriority; + }; + + struct SoundActorParam { + f32 volume; + f32 pitch; + f32 lpf; + f32 outputVolume[1]; + f32 outputPan[1]; + }; + + struct SoundHandleParam { + f32 volume; + f32 pitch; + f32 lpf; + s32 bqfType; + s32 bqfValue; + u32 outputLineFlag; + f32 outputVolume[1]; + f32 outputPan[1]; + f32 outputSurroundPan[1]; + f32 outputMainSend[1]; + f32 outputEffectSend[1][3]; + MixParameter outputMixParameter[1][2]; + MixMode mixMode; + f32 pan; + f32 surroundPan; + f32 mainSend; + f32 effectSend[3]; + s32 playerPriority; + }; + + struct ResultParam { + f32 volume; + f32 pitch; + f32 lpf; + s32 bqfType; + f32 bqfValue; + u32 outputLineFlag; + detail::OutputParam outputParamResult[1]; + s32 playerPriority; + }; + + struct FadeVolumeParam { + f32 stopFadeVolume; + f32 pauseFadeVolume; + f32 muteFadeVolume; + bool isMuted; + }; + + SoundArchiveParam soundArchiveParam; + SoundPlayerParam soundPlayerParam; + Sound3DParam sound3DParam; + SoundActorParam soundActorParam; + SoundHandleParam soundHandleParam; + ResultParam resultParam; + FadeVolumeParam fadeVolumeParam; +}; + +namespace detail { +class PlayerHeap; +class ExternalSoundPlayer; + +struct SoundActorParam { + f32 volume; + f32 pitch; + f32 tvVolume; + f32 tvPan; + f32 lpf; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + s32 biquadFilterType; + f32 biquadFilterValue; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SoundActorParam) == 0x14); +#else +static_assert(sizeof(SoundActorParam) == 0x1c); +#endif + +class BasicSound { +public: + enum State { + State_Constructed, + State_Initialized, + State_Finalized, + State_Destructed, + }; + + enum MuteState { + MuteState_Normal, + MuteState_Muting, + MuteState_Muted, + MuteState_Unmuting, + }; + + enum PauseState { + PauseState_Normal, + PauseState_Pausing, + PauseState_Paused, + PauseState_Unpausing, + }; + + enum PlayerState { + PlayerState_Init, + PlayerState_Play, + PlayerState_Stop, + }; + + struct AmbientParamUpdateCallback{}; + struct AmbientArgUpdateCallback{}; + struct AmbientArgAllocatorCallback{}; + + struct AmbientInfo { + AmbientParamUpdateCallback* paramUpdateCallback; + AmbientArgUpdateCallback* argUpdateCallback; + AmbientArgAllocatorCallback* argAllocatorCallback; + void* arg; + u64 argSize; + }; + static_assert(sizeof(AmbientInfo) == 0x28); + + struct CommonParam { + MoveValue volume; + MixMode mixMode; + f32 pan; + f32 span; + f32 send[4]; + }; + static_assert(sizeof(CommonParam) == 0x2c); + + BasicSound(); + + virtual ~BasicSound(); +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + virtual bool Initialize(); +#else + virtual bool Initialize(OutputReceiver* pOutputReceiver); +#endif + virtual void Finalize(); + virtual bool IsPrepared() const = 0; + virtual bool IsAttachedTempSpecialHandle() = 0; + virtual void DetachTempSpecialHandle() = 0; + virtual driver::BasicSoundPlayer* GetBasicSoundPlayerHandle() = 0; + virtual void OnUpdatePlayerPriority(); + virtual void UpdateMoveValue(); + virtual void OnUpdateParam(); + + void SetPriority(s32 priority, s32 ambientPriority); + void GetPriority(s32* pPlayerAvailable, s32* pPriority) const; + + void ClearIsFinalizedForCannotAllocatedResourceFlag(); + + void SetId(u32 id); + + bool IsAttachedGeneralHandle(); + void DetachGeneralHandle(); + + bool IsAttachedTempGeneralHandle(); + void DetachTempGeneralHandle(); + + void StartPrepared(); + void Stop(s32 fadeFrames); + + void SetPlayerPriority(s32 priority); + + void ForceStop(); + void Pause(bool, s32); + void Pause(bool, s32, PauseMode pauseMode); + + void Mute(bool, s32); + + void SetAutoStopCounter(s32 autoStopCounter); + + void FadeIn(s32); + + bool IsPause() const; + bool IsMute() const; + + void Update(); + void UpdateParam(); + + f32 CalculateVolume() const; + f32 CalculatePitch() const; + f32 CalculateLpfFrequency() const; + u32 CalculateOutLineFlag() const; + void CalculateBiquadFilter(s32* pBiquadFilterType, f32* pBiquadFilterValue) const; + void CalculateOutputParam(OutputParam*, OutputDevice) const; + void CalculateOutputBusMixVolume(OutputBusMixVolume*, OutputDevice) const; + + bool IsVolumeThroughModeUsed() const; + + void ApplyCommonParam(OutputParam&) const; + + void AttachPlayerHeap(PlayerHeap* heap); + void DetachPlayerHeap(PlayerHeap* heap); + + void AttachSoundPlayer(SoundPlayer* player); + void DetachSoundPlayer(SoundPlayer* player); + + void AttachSoundActor(SoundActor* actor); + void DetachSoundActor(SoundActor* actor); + + void AttachExternalSoundPlayer(ExternalSoundPlayer* extPlayer); + void DetachExternalSoundPlayer(ExternalSoundPlayer* extPlayer); + + u32 GetRemainingFadeFrames() const; + u32 GetRemainingPauseFadeFrames() const; + u32 GetRemainingMuteFadeFrames() const; + + void CalculateSoundParamCalculationValues(SoundParamCalculationValues* pParamCalcValues) const; + + void SetInitialVolume(f32 volume); + f32 GetInitialVolume() const; + + void SetVolume(f32 volume, s32 frames); + s32 GetVolume() const; + + void SetPitch(f32 pitch); + f32 GetPitch() const; + + void SetLpfFreq(f32 lpf); + f32 GetLpfFreq() const; + + void SetBiquadFilter(s32 biquadFilterType, f32 biquadFilterValue); + void GetBiquadFilter(s32*, f32*) const; + + void SetOutputLine(u32 outputLine); + u32 GetOutputLine() const; + void ResetOutputLine(); + + void SetMixMode(MixMode mode); + MixMode GetMixMode() const; + + void SetPan(f32 pan); + f32 GetPan() const; + + void SetSurroundPan(f32 surroundPan); + f32 GetSurroundPan() const; + + void SetMainSend(f32 mainSend); + f32 GetMainSend() const; + + void SetFxSend(AuxBus auxBus, f32 fxSend); + f32 GetFxSend(AuxBus auxBus) const; + + void SetSend(s32, f32 send); + void SetOutputAdditionalSend(OutputDevice device, s32, f32 send); + + f32 GetSend(s32) const; + void GetOutputAdditionalSend(OutputDevice device, s32) const; + + void SetVolumeThroughMode(s32, u8); + void SetOutputVolumeThroughMode(OutputDevice device, s32, u8); + + void GetVolumeThroughMode(s32); + void GetOutputVolumeThroughMode(OutputDevice device, s32) const; + + s32 GetSendBusCount(); + s32 GetSendChannelCount(); + +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void SetOutputAdditionalParamAddr(OutputDevice device, OutputAdditionalParam* addr, + OutputAdditionalParam* addrForPlayer); +#endif + + void SetOutputVolume(OutputDevice device, f32 volume); + void SetOutputBusMixVolume(OutputDevice, u32, u32, ChannelMixVolume); + void SetOutputChannelMixParameter(OutputDevice, u32, MixParameter); + void SetOutputPan(OutputDevice device, f32 pan); + void SetOutputSurroundPan(OutputDevice device, f32 surroundPan); + void SetOutputMainSend(OutputDevice device, f32 mainSend); + void SetOutputFxSend(OutputDevice device, AuxBus auxBus, f32 fxSend); + void SetOutputFxSend(OutputDevice device, f32 fxSend); + void SetOutputBusMixVolumeEnabled(OutputDevice device, s32, bool); + + f32 GetOutputVolume(OutputDevice device) const; + MixParameter GetOutputChannelMixParameter(OutputDevice, u32) const; + f32 GetOutputPan(OutputDevice device) const; + f32 GetOutputSurroundPan(OutputDevice device) const; + f32 GetOutputMainSend(OutputDevice device) const; + f32 GetOutputFxSend(OutputDevice device, AuxBus auxBus) const; + f32 GetOutputFxSend(OutputDevice device) const; + + bool IsOutputBusMixVolumeEnabled(OutputDevice device, s32) const; + void GetOutputBusMixVolume(OutputDevice device, s32, s32) const; + + void SetPanMode(PanMode mode); + void SetPanCurve(PanCurve curve); + void SetAmbientInfo(AmbientInfo* ambientArgInfo); + + static s32 GetAmbientPriority(const AmbientInfo& ambientInfo, u32 soundId); + + void SetSetupTick(const os::Tick& tick); + void SetSoundArchive(const SoundArchive* soundArchive); + + PanMode GetPanMode() const; + PanCurve GetPanCurve() const; + AmbientInfo* GetAmbientInfo() const; + +private: + friend SoundPlayer; + friend ExternalSoundPlayer; + + PlayerHeap* m_pPlayerHeap; + SoundHandle* m_pGeneralHandle; + SoundHandle* m_pTempGeneralHandle; + SoundPlayer* m_pSoundPlayer; + SoundActor* m_pSoundActor; + ExternalSoundPlayer* m_pExtSoundPlayer; + SoundArchive* m_pSoundArchive; + AmbientInfo m_AmbientInfo; + SoundParam m_AmbientParam; + SoundActorParam m_ActorParam; + MoveValue m_FadeVolume; + MoveValue m_PauseFadeVolume; + MoveValue m_MuteFadeVolume; + bool m_StartFlag; + bool m_StartedFlag; + bool m_AutoStopFlag; + bool m_FadeOutFlag; + bool m_PlayerAvailableFlag; + bool m_UnPauseFlag; + PauseMode m_PauseMode; + u8 m_Priority; + s8 m_BiquadFilterType; + State m_State; + u8 m_PlayerState; + u8 m_PauseState; + u8 m_MuteState; + u8 m_Padding[1]; + s32 m_AutoStopCounter; + u32 m_UpdateCounter; + u32 m_PlayingCounter; + u32 m_Id; + u32 m_InstanceId; + os::Tick m_SetupTick; + f32 m_InitVolume; + f32 m_Pitch; + f32 m_LpfFreq; + f32 m_BiquadFilterValue; + u32 m_OutputLineFlag; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* m_pOutputReceiver; +#endif + CommonParam m_CommonParam; + OutputParam m_OutputParam[1]; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputAdditionalParam* m_pOutputAdditionalParam; +#endif + void* m_pUserParam; + size_t m_UserParamSize; + SoundStopCallback m_SoundStopCallback; + util::IntrusiveListNode m_SoundPlayerPlayLink; + util::IntrusiveListNode m_SoundPlayerPriorityLink; + util::IntrusiveListNode m_ExtSoundPlayerPlayLink; + + static s32 g_LastInstanceId; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(BasicSound) == 0x1f0); +#else +static_assert(sizeof(BasicSound) == 0x210); +#endif +} // namespace detail +} // namespace nn::atk diff --git a/include/nn/atk/detail/atk_BasicSoundPlayer.h b/include/nn/atk/detail/atk_BasicSoundPlayer.h new file mode 100644 index 0000000..1c17d11 --- /dev/null +++ b/include/nn/atk/detail/atk_BasicSoundPlayer.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include +#include +#include + +namespace nn::atk::detail::driver { +struct PlayerParamSet { + + void Initialize(); + + f32 volume; + f32 pitch; + f32 lpfFreq; + f32 biquadValue; + s8 biquadType; + PanMode panMode; + PanCurve panCurve; + u32 outputLineFlag; + OutputParam tvParam; +}; +static_assert(sizeof(PlayerParamSet) == 0x70); + +class BasicSoundPlayer { +public: + virtual ~BasicSoundPlayer(); +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + virtual bool Initialize(); +#else + virtual bool Initialize(OutputReceiver* pOutputReceiver); +#endif + virtual void Finalize(); + virtual void Start() = 0; + virtual void Stop() = 0; + virtual void Pause(bool isPauseEnabled) = 0; + + BasicSoundPlayer(); + void SetBiquadFilter(s32 type, f32 value); + +private: + os::Event m_Event; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* m_pOutputReceiver; +#endif + bool m_ActiveFlag; + bool m_StartedFlag; + bool m_PauseFlag; + bool m_FinishFlag; + bool m_IsFinalizedForCannotAllocateResource; + PlayerParamSet m_PlayerParamSet; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputAdditionalParam* m_pTvAdditionalParam; +#endif + PlayerHeapDataManager* m_pPlayerHeapDataManager; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(BasicSoundPlayer) == 0xb0); +#else +static_assert(sizeof(BasicSoundPlayer) == 0xc0); +#endif +} //namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/atk_BusMixVolumePacket.h b/include/nn/atk/detail/atk_BusMixVolumePacket.h new file mode 100644 index 0000000..7e786bd --- /dev/null +++ b/include/nn/atk/detail/atk_BusMixVolumePacket.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class BusMixVolumePacket { +public: + static size_t GetRequiredMemSize(s32 busCount); + + bool Initialize(void* buffer, size_t size, s32 busCount); + void Finalize(); + + void Reset(); + +private: + OutputBusMixVolume m_BusMixVolume; + bool m_IsUsed; + bool* m_pIsEnabledTable; + s32 m_BusCount; +}; +static_assert(sizeof(BusMixVolumePacket) == 0xd8); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_Config.h b/include/nn/atk/detail/atk_Config.h new file mode 100644 index 0000000..6c47205 --- /dev/null +++ b/include/nn/atk/detail/atk_Config.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +using position_t = detail::fnd::position_t; + +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/atk_DisposeCallback.h b/include/nn/atk/detail/atk_DisposeCallback.h new file mode 100644 index 0000000..a71f557 --- /dev/null +++ b/include/nn/atk/detail/atk_DisposeCallback.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class DisposeCallback { +public: + virtual ~DisposeCallback() = default; + + virtual void InvalidateData(const void* start, const void* end) = 0; + +private: + friend class DisposeCallbackManager; + + util::IntrusiveListNode m_DisposeLink; +}; +static_assert(sizeof(DisposeCallback) == 0x18); + +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/atk_DisposeCallbackManager.h b/include/nn/atk/detail/atk_DisposeCallbackManager.h new file mode 100644 index 0000000..f615ad3 --- /dev/null +++ b/include/nn/atk/detail/atk_DisposeCallbackManager.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail::driver { +class DisposeCallbackManager { +public: + using CallbackList = util::IntrusiveList>; + + DisposeCallbackManager(); + + void RegisterDisposeCallback(DisposeCallback* callback); + void UnregisterDisposeCallback(DisposeCallback* callback); + + u64 GetCallbackCount() const; + + void Dispose(const void* mem, size_t size); + +private: + CallbackList m_CallbackList; +}; +static_assert(sizeof(DisposeCallbackManager) == 0x10); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_ElementType.h b/include/nn/atk/detail/atk_ElementType.h new file mode 100644 index 0000000..fcb4d18 --- /dev/null +++ b/include/nn/atk/detail/atk_ElementType.h @@ -0,0 +1,142 @@ +#pragma once + +namespace nn::atk::detail { +enum ElementType { + ElementType_Category_Tables = 0x100, + ElementType_Category_Parameters = 0x200, + ElementType_Category_Codecs = 0x300, + + ElementType_Category_General = 0x1F00, + + ElementType_Category_SoundArchiveFile_Blocks = 0x2000, + ElementType_Category_SoundArchiveFile_InfoSections = 0x2100, + ElementType_Category_SoundArchiveFile_ItemInfos = 0x2200, + ElementType_Category_SoundArchiveFile_Parameters = 0x2300, + ElementType_Category_SoundArchiveFile_General = 0x2400, + + ElementType_Category_StreamSoundFile_Blocks = 0x4000, + ElementType_Category_StreamSoundFile_ItemInfos = 0x4100, + + ElementType_Category_WaveSoundFile_Blocks = 0x4800, + ElementType_Category_WaveSoundFile_ItemInfos = 0x4900, + + ElementType_Category_SequenceSoundFile_Blocks = 0x5000, + ElementType_Category_SequenceSoundFile_ItemInfos = 0x5100, + + ElementType_Category_BankFile_Blocks = 0x5800, + ElementType_Category_BankFile_Items = 0x5900, + ElementType_Category_BankFile_ItemTables = 0x6000, + + ElementType_Category_WaveArchiveFile_Blocks = 0x6800, + + ElementType_Category_WaveFile_Blocks = 0x7000, + ElementType_Category_WaveFile_ItemInfos = 0x7100, + + ElementType_Category_GroupFile_Blocks = 0x7800, + ElementType_Category_GroupFile_ItemInfos = 0x7900, + + ElementType_Category_AnimSoundFile_Blocks = 0x8000, + ElementType_Category_AnimSoundFile_Items = 0x8100, + + ElementType_Table_EmbeddingTable = ElementType_Category_Tables, + ElementType_Table_ReferenceTable, + ElementType_Table_ReferenceWithSizeTable, + + ElementType_Parameter_Sound3d = ElementType_Category_Parameters, + ElementType_Parameter_Sends, + ElementType_Parameter_Envelope, + ElementType_Parameter_AdshrEnvelope, + + ElementType_Codec_DspAdpcmInfo = ElementType_Category_Codecs, + ElementType_Codec_ImaAdpcmInfo, + + ElementType_General_ByteStream = ElementType_Category_General, + ElementType_General_String, + + ElementType_SoundArchiveFile_StringBlock = ElementType_Category_SoundArchiveFile_Blocks, + ElementType_SoundArchiveFile_InfoBlock, + ElementType_SoundArchiveFile_FileBlock, + + ElementType_SoundArchiveFile_SoundInfoSection = ElementType_Category_SoundArchiveFile_InfoSections, + ElementType_SoundArchiveFile_BankInfoSection, + ElementType_SoundArchiveFile_PlayerInfoSection, + ElementType_SoundArchiveFile_WaveArchiveInfoSection, + ElementType_SoundArchiveFile_SoundGroupInfoSection, + ElementType_SoundArchiveFile_GroupInfoSection, + ElementType_SoundArchiveFile_FileInfoSection, + + ElementType_SoundArchiveFile_SoundInfo = ElementType_Category_SoundArchiveFile_ItemInfos, + ElementType_SoundArchiveFile_StreamSoundInfo, + ElementType_SoundArchiveFile_WaveSoundInfo, + ElementType_SoundArchiveFile_SequenceSoundInfo, + ElementType_SoundArchiveFile_SoundGroupInfo, + ElementType_SoundArchiveFile_WaveSoundGroupInfo, + ElementType_SoundArchiveFile_BankInfo, + ElementType_SoundArchiveFile_WaveArchiveInfo, + ElementType_SoundArchiveFile_GroupInfo, + ElementType_SoundArchiveFile_PlayerInfo, + ElementType_SoundArchiveFile_FileInfo, + ElementType_SoundArchiveFile_SoundArchivePlayerInfo, + ElementType_SoundArchiveFile_InternalFileInfo, + ElementType_SoundArchiveFile_ExternalFileInfo, + ElementType_SoundArchiveFile_StreamSoundTrackInfo, + ElementType_SoundArchiveFile_SendInfo, + ElementType_SoundArchiveFile_StreamSoundExtensionInfo, + + ElementType_SoundArchiveFile_StringTable = ElementType_Category_SoundArchiveFile_General, + ElementType_SoundArchiveFile_PatriciaTree, + + ElementType_StreamSoundFile_InfoBlock = ElementType_Category_StreamSoundFile_Blocks, + ElementType_StreamSoundFile_SeekBlock, + ElementType_StreamSoundFile_DataBlock, + ElementType_StreamSoundFile_RegionBlock, + ElementType_StreamSoundFile_PrefetchDataBlock, + + ElementType_StreamSoundFile_StreamSoundInfo = ElementType_Category_StreamSoundFile_ItemInfos, + ElementType_StreamSoundFile_TrackInfo, + ElementType_StreamSoundFile_ChannelInfo, + + ElementType_WaveSoundFile_WaveSoundMetaData = ElementType_Category_WaveSoundFile_ItemInfos, + ElementType_WaveSoundFile_WaveSoundInfo, + ElementType_WaveSoundFile_NoteInfo, + ElementType_WaveSoundFile_TrackInfo, + ElementType_WaveSoundFile_NoteEvent, + + ElementType_SequenceSoundFile_DataBlock = ElementType_Category_SequenceSoundFile_Blocks, + ElementType_SequenceSoundFile_LabelBlock, + + ElementType_SequenceSoundFile_LabelInfo = ElementType_Category_SequenceSoundFile_ItemInfos, + + ElementType_BankFile_InfoBlock = ElementType_Category_BankFile_Blocks, + + ElementType_BankFile_InstrumentInfo = ElementType_Category_BankFile_Items, + ElementType_BankFile_KeyRegionInfo, + ElementType_BankFile_VelocityRegionInfo, + ElementType_BankFile_NullInfo, + + ElementType_BankFile_DirectReferenceTable = ElementType_Category_BankFile_ItemTables, + ElementType_BankFile_RangeReferenceTable, + ElementType_BankFile_IndexReferenceTable, + + ElementType_WaveArchiveFile_InfoBlock = ElementType_Category_WaveArchiveFile_Blocks, + ElementType_WaveArchiveFile_FileBlock, + + ElementType_WaveSoundFile_InfoBlock = ElementType_Category_WaveArchiveFile_Blocks, + + ElementType_WaveFile_InfoBlock = ElementType_Category_WaveFile_Blocks, + ElementType_WaveFile_DataBlock, + + ElementType_WaveFile_ChannelInfo = ElementType_Category_WaveFile_ItemInfos, + + ElementType_GroupFile_InfoBlock = ElementType_Category_GroupFile_Blocks, + ElementType_GroupFile_FileBlock, + ElementType_GroupFile_InfoExBlock, + + ElementType_GroupFile_GroupItemInfo = ElementType_Category_GroupFile_ItemInfos, + ElementType_GroupFile_GroupItemInfoEx, + + ElementType_AnimSoundFile_DataBlock = ElementType_Category_AnimSoundFile_Blocks, + + ElementType_AnimSoundFile_EventInfo = ElementType_Category_AnimSoundFile_Items +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_ExternalSoundPlayer.h b/include/nn/atk/detail/atk_ExternalSoundPlayer.h new file mode 100644 index 0000000..c1220fc --- /dev/null +++ b/include/nn/atk/detail/atk_ExternalSoundPlayer.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail { +class ExternalSoundPlayer { +public: + using SoundList = util::IntrusiveList< + BasicSound, util::IntrusiveListMemberNodeTraits< + BasicSound, &BasicSound::m_ExtSoundPlayerPlayLink>>; + + virtual ~ExternalSoundPlayer(); + virtual bool CanPlaySound(s32); + + ExternalSoundPlayer(); + + void StopAllSound(s32 fadeFrames); + void PauseAllSound(bool, s32); + void PauseAllSound(bool, s32, PauseMode); + + void Finalize(SoundActor* actor); + + void RemoveSound(BasicSound* sound); + bool AppendSound(BasicSound* sound); + + BasicSound* GetLowestPrioritySound(); + + void SetPlayableSoundCount(s32 count); + + bool CanPlaySound(); + +private: + SoundList m_SoundList; + s32 m_PlayableCount; +}; +static_assert(sizeof(ExternalSoundPlayer) == 0x20); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_GroupFile.h b/include/nn/atk/detail/atk_GroupFile.h new file mode 100644 index 0000000..9e5d70e --- /dev/null +++ b/include/nn/atk/detail/atk_GroupFile.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct GroupFile { + struct InfoBlock; + struct FileBlock; + struct InfoExBlock; + struct FileHeader : Util::SoundFileHeader { + + InfoBlock* GetInfoBlock() const; + FileBlock* GetFileBlock() const; + InfoExBlock* GetInfoExBlock() const; + + }; + + struct InfoBlockBody { + Util::ReferenceTable referenceTableOfGroupItemInfo; + }; + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + + struct FileBlockBody {/* unknown structure */}; + + struct FileBlock { + BinaryBlockHeader header; + FileBlockBody body; + }; + + struct InfoExBlockBody { + Util::ReferenceTable referenceTableOfGroupItemInfoEx; + }; + + struct InfoExBlock { + BinaryBlockHeader header; + InfoExBlockBody body; + }; + + struct GroupItemInfo { + constexpr static s32 OffsetForLink = -1; + constexpr static s32 SizeForLink = -1; + + u32 fileId; + Util::ReferenceWithSize embeddedItemInfo; + }; + static_assert(sizeof(GroupItemInfo) == 0x10); + + struct GroupItemInfoEx { + u32 itemId; + u32 loadFlag; + }; + static_assert(sizeof(GroupItemInfoEx) == 0x8); + +}; + +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_GroupFileReader.h b/include/nn/atk/detail/atk_GroupFileReader.h new file mode 100644 index 0000000..1f4eba2 --- /dev/null +++ b/include/nn/atk/detail/atk_GroupFileReader.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct GroupItemLocationInfo { + u32 fileId; + void* address; +}; +static_assert(sizeof(GroupItemLocationInfo) == 0x10); + +class GroupFileReader { +public: + constexpr static s64 SignatureFile = 0x50524746; // FGRP + + explicit GroupFileReader(const void* groupFile); + + bool ReadGroupItemLocationInfo(GroupItemLocationInfo* out, u32 index) const; + + u32 GetGroupItemExCount() const; + + bool ReadGroupItemInfoEx(GroupFile::GroupItemInfoEx* out, u32 index) const; + +private: + GroupFile::InfoBlockBody* m_pInfoBlockBody; + GroupFile::FileBlockBody* m_pFileBlockBody; + GroupFile::InfoExBlockBody* m_pInfoExBlockBody; +}; +static_assert(sizeof(GroupFileReader) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_IRegionInfoReadable.h b/include/nn/atk/detail/atk_IRegionInfoReadable.h new file mode 100644 index 0000000..0352f6d --- /dev/null +++ b/include/nn/atk/detail/atk_IRegionInfoReadable.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class IRegionInfoReadable { +public: + virtual ~IRegionInfoReadable() = default; + + virtual bool ReadRegionInfo(StreamSoundFile::RegionInfo* pInfo, + u32 regionIndex) const = 0; +}; +static_assert(sizeof(IRegionInfoReadable) == 0x8); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_IStreamDataDecoder.h b/include/nn/atk/detail/atk_IStreamDataDecoder.h new file mode 100644 index 0000000..98cff4d --- /dev/null +++ b/include/nn/atk/detail/atk_IStreamDataDecoder.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail { +namespace driver { +class StreamSoundPlayer; +} // namespace nn::atk::detail::driver + +class IStreamDataDecoder { +public: + enum DecodeType { + DecodeType_Normal, + DecodeType_Loop, + DecodeType_Idling, + DecodeType_Count + }; + + struct DataInfo { + s32 channelCount; + s32 sampleRate; + s32 blockSampleCount; + size_t blockSize; + }; + static_assert(sizeof(DataInfo) == 0x18); + + struct DecodeProfile { + os::Tick decodeTick; + s32 decodedSampleCount; + os::Tick fsAccessTick; + size_t fsReadSize; + }; + static_assert(sizeof(DecodeProfile) == 0x20); + + struct CacheProfile { + position_t cacheStartPosition; + size_t cachedLength; + position_t cacheCurrentPosition; + driver::StreamSoundPlayer* player; + }; + static_assert(sizeof(CacheProfile) == 0x20); + + virtual ~IStreamDataDecoder(); +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_IntrusiveList.h b/include/nn/atk/detail/atk_IntrusiveList.h new file mode 100644 index 0000000..def3e50 --- /dev/null +++ b/include/nn/atk/detail/atk_IntrusiveList.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace nn::atk::detail { +using IntrusiveListNode = util::IntrusiveListNode; + +template +class IntrusiveList { +public: + using ElementList = util::IntrusiveList>; + using Iterator = typename ElementList::iterator; + using ConstIterator = typename ElementList::const_iterator; + +private: + ElementList m_ListImpl; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_ItemType.h b/include/nn/atk/detail/atk_ItemType.h new file mode 100644 index 0000000..574f6ca --- /dev/null +++ b/include/nn/atk/detail/atk_ItemType.h @@ -0,0 +1,12 @@ +#pragma once + +namespace nn::atk::detail { +enum ItemType { + ItemType_Sound = 1, + ItemType_SoundGroup, + ItemType_Bank, + ItemType_Player, + ItemType_WaveArchive, + ItemType_Group, +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_LoaderManager.h b/include/nn/atk/detail/atk_LoaderManager.h new file mode 100644 index 0000000..0d4cbbd --- /dev/null +++ b/include/nn/atk/detail/atk_LoaderManager.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace nn::atk::detail { +template +class LoaderManager : driver::SoundThread::SoundFrameCallback { +public: + using List = util::IntrusiveList>; + using Iterator = typename List::iterator; + + LoaderManager(); + ~LoaderManager() override; + + void OnBeginSoundFrame() override; + + void Destroy(); + +private: + void* m_pBuffer; + size_t m_BufferSize; + List m_FreeList; + List m_FreeReqList; +}; + +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_MoveValue.h b/include/nn/atk/detail/atk_MoveValue.h new file mode 100644 index 0000000..0a8ea46 --- /dev/null +++ b/include/nn/atk/detail/atk_MoveValue.h @@ -0,0 +1,13 @@ +#pragma once + +namespace nn::atk::detail { +template +class MoveValue { +public: +private: + T1 m_Origin; + T1 m_Target; + T2 m_Frame; + T2 m_Counter; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_NoteOnCallback.h b/include/nn/atk/detail/atk_NoteOnCallback.h new file mode 100644 index 0000000..4f64e69 --- /dev/null +++ b/include/nn/atk/detail/atk_NoteOnCallback.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class SequenceSoundPlayer; + +struct NoteOnInfo { + s32 prgNo; + s32 key; + s32 velocity; + s32 length; + s32 initPan; + s32 priority; + Channel::ChannelCallback channelCallback; + void* channelCallbackData; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pOutputReceiver; +#endif + UpdateType updateType; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(NoteOnInfo) == 0x30); +#else +static_assert(sizeof(NoteOnInfo) == 0x38); +#endif + +class NoteOnCallback { +public: + virtual ~NoteOnCallback(); + virtual Channel* NoteOn(SequenceSoundPlayer* seqPlayer, u8 bankIndex, + const NoteOnInfo& noteOnInfo) = 0; +}; +static_assert(sizeof(NoteOnCallback) == 0x8); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_OutputAdditionalParam.h b/include/nn/atk/detail/atk_OutputAdditionalParam.h new file mode 100644 index 0000000..bd4d02b --- /dev/null +++ b/include/nn/atk/detail/atk_OutputAdditionalParam.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include +#include +#include + +namespace nn::atk::detail { +using SendArray = ValueArray; + +class OutputAdditionalParam { +public: + static size_t GetRequiredMemSize(const SoundInstanceConfig& config); + + void Initialize(void* buffer, size_t bufferSize, const SoundInstanceConfig& config); + void Finalize(); + + void Reset(); + + void* GetBufferAddr(); + + SendArray* GetAdditionalSendAddr(); + SendArray* GetAdditionalSendAddr() const; + + f32 TryGetAdditionalSend(s32 bus) const; + + bool IsAdditionalSendEnabled() const; + + void TrySetAdditionalSend(s32 bus, f32 send); + + BusMixVolumePacket* GetBusMixVolumePacketAddr(); + BusMixVolumePacket* GetBusMixVolumePacketAddr() const; + + f32 GetBusMixVolume(s32 waveChannel, s32 mixChannel) const; + OutputBusMixVolume* GetBusMixVolume() const; + + void SetBusMixVolume(s32 waveChannel, s32 mixChannel, f32 volume); + void SetBusMixVolume(const OutputBusMixVolume& param); + + bool IsBusMixVolumeUsed() const; + void SetBusMixVolumeUsed(bool isUsed); + + bool IsBusMixVolumeEnabledForBus(s32 bus) const; + void SetBusMixVolumeEnabledForBus(s32 bus, bool isEnabled); + + bool IsBusMixVolumeEnabled() const; + + VolumeThroughModePacket* GetVolumeThroughModePacketAddr(); + VolumeThroughModePacket* GetVolumeThroughModePacketAddr() const; + + f32 GetBinaryVolume() const; + void SetBinaryVolume(f32 volume); + + u8 TryGetVolumeThroughMode(s32 bus) const; + void TrySetVolumeThroughMode(s32 bus, u8 volumeThroughMode); + bool IsVolumeThroughModeEnabled() const; + + bool IsVolumeThroughModeUsed(); + void SetVolumeThroughModeUsed(bool isUsed); + + OutputAdditionalParam& operator=(const OutputAdditionalParam& rhs); + +private: + SendArray* m_pAdditionalSend; + BusMixVolumePacket* m_pBusMixVolumePacket; + VolumeThroughModePacket* VolumeThroughModePacket; +}; +static_assert(sizeof(OutputAdditionalParam) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_PlayerHeap.h b/include/nn/atk/detail/atk_PlayerHeap.h new file mode 100644 index 0000000..b7f854b --- /dev/null +++ b/include/nn/atk/detail/atk_PlayerHeap.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +class SoundPlayer; + +namespace detail { +class PlayerHeap; +class CallbackNode { +private: + friend PlayerHeap; + + util::IntrusiveListNode m_Link; + SoundMemoryAllocatable::DisposeCallback m_Callback; + void* m_CallbackArg; +}; +static_assert(sizeof(CallbackNode) == 0x20); + +class PlayerHeap : SoundMemoryAllocatable { +public: + using CallbackList = util::IntrusiveList< + CallbackNode, util::IntrusiveListMemberNodeTraits< + CallbackNode, &CallbackNode::m_Link>>; + + PlayerHeap(); + ~PlayerHeap() override; + + void Destroy(); + + bool Create(void* startAddress, size_t size); + + void Clear(); + + void* Allocate(size_t size) override; + void* Allocate(size_t size, SoundMemoryAllocatable::DisposeCallback callback, + void* callbackArg) override; + + size_t GetAllocateSize(size_t size, bool needMemoryPool) override; + size_t GetFreeSize() const; + +private: + friend SoundPlayer; + + SoundPlayer* m_pPlayer; + void* m_pStartAddress; + void* m_pEndAddress; + void* m_pAllocAddress; + u8 m_State; + u8 m_Padding[3]; + util::IntrusiveListNode m_Link; + CallbackList m_CallbackList; +}; +static_assert(sizeof(PlayerHeap) == 0x50); +} // namespace nn::atk::detail +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/atk_PlayerHeapDataManager.h b/include/nn/atk/detail/atk_PlayerHeapDataManager.h new file mode 100644 index 0000000..1011834 --- /dev/null +++ b/include/nn/atk/detail/atk_PlayerHeapDataManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class PlayerHeapDataManager : driver::DisposeCallback, SoundArchiveLoader { +public: + constexpr static u8 FileAddressCount = 9; + + struct FileAddress { + SoundArchive::FileId fileId; + void* address; + }; + static_assert(sizeof(FileAddress) == 0x10); + + PlayerHeapDataManager(); + ~PlayerHeapDataManager() override; + + void Finalize(); + void Initialize(const SoundArchive* arc); + + void* SetFileAddress(SoundArchive::FileId fileId, const void* address); + void* GetFileAddress(SoundArchive::FileId fileId) const; + + void InvalidateData(const void* start, const void* end) override; + + void* SetFileAddressToTable(SoundArchive::FileId fileId, const void* address) override; + void* GetFileAddressFromTable(SoundArchive::FileId fileId) const override; + void* GetFileAddressImpl(SoundArchive::FileId fileId) const override; + +private: + FileAddress m_FileAddress[FileAddressCount]; + bool m_IsInitialized; + bool m_IsFinalized; +}; +static_assert(sizeof(PlayerHeapDataManager) == 0x2c8); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_RegionManager.h b/include/nn/atk/detail/atk_RegionManager.h new file mode 100644 index 0000000..d6ecf2e --- /dev/null +++ b/include/nn/atk/detail/atk_RegionManager.h @@ -0,0 +1,84 @@ +#pragma once + +#include + +#include +#include +#include + +namespace nn::atk { +enum StreamRegionCallbackResult { + StreamRegionCallbackResult_Finish, + StreamRegionCallbackResult_Continue, +}; + +struct StreamRegionCallbackParam { + s32 regionNo; + char regionName[64]; + bool isRegionNameEnabled; + s32 regionCount; + detail::IRegionInfoReadable* pRegionInfoReader; +}; +static_assert(sizeof(StreamRegionCallbackParam) == 0x58); + +using StreamRegionCallback = StreamRegionCallbackResult(*)(StreamRegionCallbackParam*,void*); + +namespace detail { +struct StreamDataInfoDetail; + +class RegionManager { +public: + struct Region { + position_t current; + position_t begin; + position_t end; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + bool isEnabled; +#endif + }; + + void Initialize(); + bool InitializeRegion(IRegionInfoReadable* pRegionReader, + StreamDataInfoDetail* pStreamDataInfo); + + bool IsPreparedForRegionJump() const; + + bool ChangeRegion(s32 currentRegionNo, IRegionInfoReadable* pRegionReader, + StreamDataInfoDetail* pStreamDataInfo); + + bool SetRegionInfo(const StreamSoundFile::RegionInfo* pRegionInfo, + const StreamDataInfoDetail* pStreamDataInfo); + + bool TryMoveNextRegion(IRegionInfoReadable* pRegionReader, + StreamDataInfoDetail* pStreamDataInfo); + + void SetPosition(position_t position); + void AddPosition(position_t position); + + bool IsInFirstRegion() const; + +private: + bool m_IsRegionInfoEnabled; + bool m_IsRegionIndexCheckEnabled; + bool m_IsRegionInitialized; + bool m_IsCurrentRegionNameEnabled; + StreamRegionCallback m_StreamRegionCallbackFunc; + void* m_StreamRegionCallbackArg; + s32 m_CurrentRegionNo; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + char* m_pCurrentRegionName; +#endif + Region m_CurrentRegion; + position_t m_AdpcmContextForStartOffsetFrame; + AdpcmContext m_AdpcmContextForStartOffset[16]; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + char m_CurrentRegionName[64]; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(RegionManager) == 0x440); +#else +static_assert(sizeof(RegionManager) == 0x4c0); +#endif +} // namespace nn::atk::detail +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/atk_SoundArchiveFile.h b/include/nn/atk/detail/atk_SoundArchiveFile.h new file mode 100644 index 0000000..cb71738 --- /dev/null +++ b/include/nn/atk/detail/atk_SoundArchiveFile.h @@ -0,0 +1,360 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +struct SoundArchiveParametersHook; + +class SoundArchiveFile { +public: + constexpr static u32 BlockCount = 3; + + struct FileHeader : BinaryFileHeader { + + Util::ReferenceWithSize* GetReferenceBy(u16) const; + + u32 GetStringBlockSize() const; + u32 GetInfoBlockSize() const; + u32 GetFileBlockSize() const; + + s32 GetStringBlockOffset() const; + s32 GetInfoBlockOffset() const; + s32 GetFileBlockOffset() const; + + Util::ReferenceWithSize toBlocks[BlockCount]; + }; + static_assert(sizeof(FileHeader) == 0x38); + + struct StringBlockBody { + enum Sections { + Sections_StringTable, + Sections_PatriciaTree, + Sections_Max, + }; + + void* GetSection(Sections section) const; + char* GetString(u32) const; + u32 GetItemIdImpl(Sections section, char* str) const; + + void DumpTree() const; + + Util::Reference toSection[1]; + }; + + struct StringBlock { + BinaryBlockHeader header; + StringBlockBody body; + }; + + struct PatriciaTree { + struct NodeData { + u32 stringId; + u32 itemId; + }; + static_assert(sizeof(NodeData) == 0x8); + + struct Node { + constexpr static u32 FlagLeaf = 1; + + u16 flags; + u16 bit; + u32 leftIdx; + u32 rightIdx; + NodeData nodeData; + }; + static_assert(sizeof(Node) == 0x14); + + void* GetNodeDataBy(const char*, u64); + + u32 rootIdx; + Util::Table nodeTable; + }; + + struct SoundInfo; + struct BankInfo; + struct PlayerInfo; + struct SoundGroupInfo; + struct GroupInfo; + struct WaveArchiveInfo; + struct FileInfo; + struct SoundArchivePlayerInfo; + struct InfoBlockBody { + + SoundInfo* GetSoundInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetSoundInfoReferenceTable() const; + + BankInfo* GetBankInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetBankInfoReferenceTable() const; + + PlayerInfo* GetPlayerInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetPlayerInfoReferenceTable() const; + + SoundGroupInfo* GetSoundGroupInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetSoundGroupInfoReferenceTable() const; + + GroupInfo* GetGroupInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetGroupInfoReferenceTable() const; + + WaveArchiveInfo* GetWaveArchiveInfo(SoundArchive::ItemId itemId) const; + Util::ReferenceTable* GetWaveArchiveInfoReferenceTable() const; + + FileInfo* GetFileInfo(SoundArchive::FileId itemId) const; + Util::ReferenceTable* GetFileInfoReferenceTable() const; + + SoundArchive::FileId GetItemFileId(SoundArchive::ItemId id) const; + SoundArchive::FileId GetItemPrefetchFileId(SoundArchive::ItemId id) const; + SoundArchive::StringId GetItemStringId(SoundArchive::ItemId id) const; + + SoundArchivePlayerInfo* GetSoundArchivePlayerInfo() const; + + Util::Reference toSoundInfoReferenceTable; + Util::Reference toSoundGroupInfoReferenceTable; + Util::Reference toBankInfoReferenceTable; + Util::Reference toWaveArchiveInfoReferenceTable; + Util::Reference toGroupInfoReferenceTable; + Util::Reference toPlayerInfoReferenceTable; + Util::Reference toFileInfoReferenceTable; + Util::Reference toSoundArchivePlayerInfo; + }; + static_assert(sizeof(InfoBlockBody) == 0x40); + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + static_assert(sizeof(InfoBlock) == 0x48); + + struct StreamSoundInfo; + struct WaveSoundInfo; + struct AdvancedWaveSoundInfo; + struct SequenceSoundInfo; + struct Sound3DInfo; + struct SoundInfo { + + SoundArchive::SoundType GetSoundType() const; + StreamSoundInfo* GetStreamSoundInfo() const; + + SoundArchive::StringId GetStringId() const; + + WaveSoundInfo* GetWaveSoundInfo() const; + AdvancedWaveSoundInfo* GetAdvancedWaveSoundInfo() const; + SequenceSoundInfo* GetSequenceSoundInfo() const; + Sound3DInfo* GetSound3DInfo() const; + + PanMode GetPanMode() const; + PanCurve GetPanCurve() const; + SinglePlayType GetSinglePlayType() const; + u16 GetSinglePlayEffectiveDuration() const; + u8 GetPlayerPriority() const; + u8 GetActorPlayerId() const; + u32 GetUserParam() const; + + bool ReadUserParam(u32*, s32) const; + + bool IsFrontBypass() const; + + u32 fileId; + u32 playerId; + u8 volume; + u8 remoteFilter; + u8 padding[2]; + Util::Reference toDetailSoundInfo; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(SoundInfo) == 0x18); + + struct StreamTrackInfo { + u8 volume; + u8 pan; + u8 span; + u8 flags; + Util::Reference toGlobalChannelIndexTable; + Util::Reference toSendValue; + u8 lpfFreq; + u8 biquadType; + u8 biquadValue; + u8 padding[1]; + }; + static_assert(sizeof(StreamTrackInfo) == 0x18); + + struct StreamTrackInfoTable { + Util::ReferenceTable table; + }; + + struct StreamSoundExtension { + u32 streamTypeInfo; + u32 loopStartFrame; + u32 loopEndFrame; + }; + static_assert(sizeof(StreamSoundExtension) == 0xc); + + struct SendValue { + u8 mainSend; + u8 fxSend[3]; + }; + static_assert(sizeof(SendValue) == 0x4); + + struct StreamSoundInfo { + + StreamTrackInfoTable* GetTrackInfoTable() const; + StreamSoundExtension* GetStreamSoundExtension() const; + SendValue* GetSendValue() const; + + u16 allocateTrackFlags; + u16 allocateChannelCount; + Util::Reference toTrackInfoTable; + f32 pitch; + Util::Reference toSendValue; + Util::Reference toStreamSoundExtension; + u32 prefetchFileId; + }; + static_assert(sizeof(StreamSoundInfo) == 0x24); + + struct WaveSoundInfo { + + u8 GetChannelPriority() const; + u8 GetIsReleasePriorityFix() const; + + u32 index; + u32 allocateTrackCount; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(WaveSoundInfo) == 0xc); + + struct AdvancedWaveSoundInfo { + u32 waveArchiveId; + }; + static_assert(sizeof(AdvancedWaveSoundInfo) == 0x4); + + struct SequenceSoundInfo { + + Util::ReferenceTable* GetBankIdTable() const; + void GetBankIds(u32* bankIds) const; + u32 GetStartOffset() const; + u8 GetChannelPriority() const; + + bool IsReleasePriorityFix() const; + + Util::Reference toBankIdTable; + u32 allocateTrackFlags; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(SequenceSoundInfo) == 0x10); + + struct Sound3DInfo { + u32 flags; + f32 decayRatio; + u8 decayCurve; + u8 dopplerFactor; + u8 padding[2]; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(Sound3DInfo) == 0x10); + + struct BankInfo { + + SoundArchive::StringId GetStringId() const; + + u32 fileId; + Util::Reference toWaveArchiveItemIdTable; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(BankInfo) == 0x10); + + struct PlayerInfo { + + SoundArchive::StringId GetStringId() const; + u32 GetPlayerHeapSize() const; + + u32 playableSoundMax; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(PlayerInfo) == 0x8); + + struct SoundGroupInfo { + + SoundArchive::StringId GetStringId() const; + + u32 startId; + u32 endId; + Util::Reference toFileIdTable; + Util::Reference toDetailSoundGroupInfo; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(SoundGroupInfo) == 0x1c); + + struct GroupInfo { + + SoundArchive::StringId GetStringId() const; + + u32 fileId; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(GroupInfo) == 0x8); + + struct WaveArchiveInfo { + + SoundArchive::StringId GetStringId() const; + u32 GetWaveCount() const; + + u32 fileId; + bool isLoadIndividual; + u8 padding[3]; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(WaveArchiveInfo) == 0xc); + + struct SoundArchivePlayerInfo { + u16 sequenceSoundCount; + u16 sequenceTrackCount; + u16 streamSoundCount; + u16 streamTrackCount; + u16 streamChannelCount; + u16 waveSoundCount; + u16 waveTrackCount; + u8 streamBufferTimes; + u8 developFlags; + u32 options; + }; + static_assert(sizeof(SoundArchivePlayerInfo) == 0x14); + + struct WaveSoundGroupInfo { + Util::Reference toWaveArchiveItemIdTable; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(WaveSoundGroupInfo) == 0xc); + + enum FileLocationType { + FileLocationType_Internal, + FileLocationType_External, + FileLocationType_None, + }; + + struct InternalFileInfo { + constexpr static s32 InvalidOffset = -1; + constexpr static s32 InvalidSize = -1; + + Util::ReferenceWithSize toFileImageFromFileBlockBody; + Util::Reference toAttachedGroupIdTable; + }; + static_assert(sizeof(InternalFileInfo) == 0x14); + + struct ExternalFileInfo { + char filePath[1]; + }; + + struct FileInfo { + + FileLocationType GetFileLocationType() const; + InternalFileInfo* GetInternalFileInfo() const; + ExternalFileInfo* GetExternalFileInfo() const; + + Util::Reference toFileLocation; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(FileInfo) == 0xc); + + struct FileBlock {}; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_SoundArchiveFileReader.h b/include/nn/atk/detail/atk_SoundArchiveFileReader.h new file mode 100644 index 0000000..4a326f8 --- /dev/null +++ b/include/nn/atk/detail/atk_SoundArchiveFileReader.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class SoundArchiveFileReader { +public: + constexpr static s32 SignatureFile = 0x52415346; // FSAR + constexpr static s32 InvalidOffset = -1; + constexpr static s32 InvalidSize = -1; + + SoundArchiveFileReader(); + + void Initialize(const void* soundArchiveData); + void Finalize(); + + bool IsStreamSendAvailable() const; + bool IsFilterSupportedVersion() const; + bool IsStreamPrefetchAvailable() const; + + void SetStringBlock(const void* stringBlock); + void SetInfoBlock(const void* infoBlock); + + s32 GetStringCount() const; + char* GetString(u32) const; + + void DumpTree() const; + + SoundArchive::ItemId GetItemId(const char* pStr); + char* GetItemLabel(SoundArchive::ItemId id) const; + + SoundArchive::FileId GetItemFileId(SoundArchive::ItemId id) const; + SoundArchive::FileId GetItemPrefetchFileId(SoundArchive::ItemId id) const; + + s32 GetSoundCount() const; + s32 GetBankCount() const; + s32 GetPlayerCount() const; + s32 GetSoundGroupCount() const; + s32 GetGroupCount() const; + s32 GetWaveArchiveCount() const; + s32 GetFileCount() const; + + bool ReadSoundInfo(SoundArchive::ItemId soundId, SoundArchive::SoundInfo* info) const; + bool ReadBankInfo(SoundArchive::ItemId bankId, SoundArchive::BankInfo* info) const; + bool ReadPlayerInfo(SoundArchive::ItemId playerId, SoundArchive::PlayerInfo* info) const; + bool ReadSoundGroupInfo(SoundArchive::ItemId soundGroupId, SoundArchive::SoundGroupInfo* info) const; + bool ReadGroupInfo(SoundArchive::ItemId groupId, SoundArchive::GroupInfo* info) const; + bool ReadFileInfo(SoundArchive::FileId id, SoundArchive::FileInfo* info, s32 index) const; + bool ReadWaveArchiveInfo(SoundArchive::ItemId warcId, SoundArchive::WaveArchiveInfo* info) const; + bool ReadSoundArchivePlayerInfo(SoundArchive::SoundArchivePlayerInfo* info) const; + bool ReadSound3DInfo(SoundArchive::ItemId soundId, SoundArchive::Sound3DInfo* info) const; + bool ReadSequenceSoundInfo(SoundArchive::ItemId soundId, SoundArchive::SequenceSoundInfo* info) const; + bool ReadStreamSoundInfo(SoundArchive::ItemId soundId, SoundArchive::StreamSoundInfo* info) const; + bool ReadStreamSoundInfo2(SoundArchive::ItemId soundId, SoundArchive::StreamSoundInfo2* info) const; + bool ReadWaveSoundInfo(SoundArchive::ItemId soundId, SoundArchive::WaveSoundInfo* info) const; + bool ReadAdvancedWaveSoundInfo(SoundArchive::ItemId soundId, SoundArchive::AdvancedWaveSoundInfo* info) const; + + Util::Table* GetWaveArchiveIdTable(SoundArchive::ItemId id) const; + SoundArchive::SoundType GetSoundType(SoundArchive::ItemId soundId) const; + u32 GetSoundUserParam(u32) const; + + bool ReadSoundUserParam(u32*, u32, s32) const; + void* GetAttachedGroupTable(u32) const; // unknown return type + +private: + SoundArchiveFile::FileHeader m_Header; + SoundArchiveFile::StringBlockBody* m_pStringBlockBody; + SoundArchiveFile::InfoBlockBody* m_pInfoBlockBody; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + SoundArchiveFile::FileBlock* m_pFileBlock; +#endif +}; + +struct SoundArchiveFilesHook { + constexpr static const char* ItemTypeStreamSound = "stm"; + constexpr static const char* ItemTypeWaveSound = "wsd"; + constexpr static const char* ItemTypeSequenceSound = "seq"; + + constexpr static const char* FileTypeStreamBinary = "bxstm"; + constexpr static const char* FileTypeWaveSoundBinary = "bxwsd"; + constexpr static const char* FileTypeSequenceBinary = "bxseq"; + constexpr static const char* FileTypeBankBinary = "bxbnk"; + constexpr static const char* FileTypeWaveArchiveBinary = "bxwar"; + constexpr static const char* FileTypeStreamPrefetchBinary = "bxstp"; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_SoundArchiveLoader.h b/include/nn/atk/detail/atk_SoundArchiveLoader.h new file mode 100644 index 0000000..c2c2d97 --- /dev/null +++ b/include/nn/atk/detail/atk_SoundArchiveLoader.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +struct LoadItemInfo { + SoundArchive::ItemId itemId; + void* address; +}; +static_assert(sizeof(LoadItemInfo) == 0x10); + +class SoundArchiveLoader { +public: + enum LoadFlag { + LoadFlag_All = -1, + LoadFlag_Seq = 1, + LoadFlag_Wsd = 2, + LoadFlag_Bank = 4, + LoadFlag_Warc = 8, + }; + + constexpr static s32 SignatureIndividualWave = 0x56574946; // FWIV + constexpr static u8 WaveBufferAlignSize = 64; + + struct IndividualWaveInfo { + u32 signature; + u32 fileId; + u32 waveIndex; + u32 padding[5]; + u32 padding2[8]; + }; + static_assert(sizeof(IndividualWaveInfo) == 0x40); + + SoundArchiveLoader(); + virtual ~SoundArchiveLoader(); + + virtual void* SetFileAddressToTable(SoundArchive::FileId fileId, const void* address) = 0; + virtual void* GetFileAddressFromTable(SoundArchive::FileId fileId) const = 0; + virtual void* GetFileAddressImpl(SoundArchive::FileId fileId) const = 0; + + void SetSoundArchive(const SoundArchive* arc); + + bool IsAvailable() const; + + bool LoadData(SoundArchive::ItemId itemId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + bool LoadSequenceSound(SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + bool LoadAdvancedWaveSound(SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + bool LoadWaveSound(SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize, SoundArchive::ItemId waveSoundSetId); + bool LoadStreamSoundPrefetch(SoundArchive::ItemId soundId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize); + bool LoadBank(SoundArchive::ItemId bankId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + bool LoadWaveArchive(SoundArchive::ItemId bankId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + bool LoadGroup(SoundArchive::ItemId soundGroupId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize); + bool LoadSoundGroup(SoundArchive::ItemId soundGroupId, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + + bool LoadData(char* pItemName, SoundMemoryAllocatable* pAllocator, + u32 loadFlag, size_t loadBlockSize); + void* LoadImpl(SoundArchive::FileId fileId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize, bool needMemoryPool); + void* LoadFile(SoundArchive::FileId fileId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize, bool needMemoryPool); + + void* LoadWaveArchiveImpl(SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize, bool needMemoryPool); + bool LoadIndividualWave(SoundArchive::ItemId warcId, u32 waveIndex, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize); + void* LoadWaveArchiveTable(SoundArchive::ItemId warcId, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize); + + size_t ReadFile(SoundArchive::FileId fileId, void* buffer, size_t size, s32 offset, + size_t loadBlockSize); + + bool PostProcessForLoadedGroupFile(void* pGroupFile, SoundMemoryAllocatable* pAllocator, + size_t loadBlockSize); + + void SetWaveArchiveTableWithSeqInEmbeddedGroup(SoundArchive::ItemId seqId, + SoundMemoryAllocatable* pAllocator); + void SetWaveArchiveTableWithBankInEmbeddedGroup(SoundArchive::ItemId bankId, + SoundMemoryAllocatable* pAllocator); + void SetWaveArchiveTableWithWsdInEmbeddedGroup(SoundArchive::ItemId wsdId, + SoundMemoryAllocatable* pAllocator); + void SetWaveArchiveTableInEmbeddedGroupImpl(SoundArchive::ItemId warcId, + SoundMemoryAllocatable* pAllocator); + + bool IsDataLoaded(const char*, u32) const; + bool IsDataLoaded(u32, u32) const; + + bool IsSequenceSoundDataLoaded(u32, u32) const; + bool IsWaveSoundDataLoaded(u32, u32) const; + bool IsBankDataLoaded(u32, u32) const; + bool IsWaveArchiveDataLoaded(u32, u32) const; + bool IsGroupDataLoaded(u32) const; + bool IsSoundGroupDataLoaded(u32, u32) const; + + void* GetFileAddressFromSoundArchive(SoundArchive::FileId fileId) const; + + void* detail_GetFileAddressByItemId(SoundArchive::ItemId itemId) const; + + bool detail_LoadWaveArchiveByBankFile(void* bankFile, + SoundMemoryAllocatable* pAllocator); + bool detail_LoadWaveArchiveByWaveSoundFile(void* wsdFile, s32 wsdIndex, + SoundMemoryAllocatable* pAllocator); + +private: + SoundArchive* m_pSoundArchive; + u32 m_StreamArea[128]; + u16 m_LoadDataCallCount; + bool m_IsCancelLoading; +}; +static_assert(sizeof(SoundArchiveLoader) == 0x218); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_SoundArchiveManager.h b/include/nn/atk/detail/atk_SoundArchiveManager.h new file mode 100644 index 0000000..58b31c3 --- /dev/null +++ b/include/nn/atk/detail/atk_SoundArchiveManager.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include + +namespace nn::atk::detail { +class SoundArchiveManager { +public: + using ContainerList = IntrusiveList; + + class SnapShot { + public: + private: + SoundArchive* m_MainSoundArchive; + SoundDataManager* m_MainSoundDataManager; + SoundArchive* m_CurrentSoundArchive; + SoundDataManager* m_CurrentSoundDataManager; + }; + + SoundArchiveManager(); + ~SoundArchiveManager(); + + void Initialize(const SoundArchive* pSoundArchive, const SoundDataManager* pSoundDataManager); + + void ChangeTargetArchive(const char* soundArchiveName); + + void Finalize(); + + void Add(AddonSoundArchiveContainer&); + void Remove(AddonSoundArchiveContainer&); + + bool IsAvailable() const; + + AddonSoundArchive* GetAddonSoundArchive(const char*) const; + SoundDataManager* GetAddonSoundDataManager(const char*) const; + AddonSoundArchiveContainer* GetAddonSoundArchiveContainer(s32) const; + AddonSoundArchiveContainer* GetAddonSoundArchiveContainer(s32); + + void SetParametersHook(SoundArchiveParametersHook*); + SoundArchiveParametersHook* GetParametersHook() const; + +private: + SoundArchive* m_pMainSoundArchive; + SoundDataManager* m_pMainSoundDataManager; + ContainerList m_ContainerList; + SoundArchive* m_pCurrentSoundArchive; + SoundDataManager* m_pCurrentSoundDataManager; + SoundArchiveParametersHook* m_pParametersHook; +}; +static_assert(sizeof(SoundArchiveManager) == 0x38); +} // namespace nn::atk::detail diff --git a/include/nn/atk/detail/atk_SoundInstanceManager.h b/include/nn/atk/detail/atk_SoundInstanceManager.h new file mode 100644 index 0000000..aadf7d0 --- /dev/null +++ b/include/nn/atk/detail/atk_SoundInstanceManager.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nn::atk::detail { +template +class SoundInstanceManager { +public: + using PriorityList = util::IntrusiveList>; + using Iterator = typename PriorityList::iterator; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + T* Alloc(s32 priority, s32 ambientPriority); +#else + T* Alloc(s32 priority, s32 ambientPriority, OutputReceiver* pOutputReceiver); +#endif + s32 Create(void* buffer, size_t size, const SoundInstanceConfig& config); + + void SortPriorityList(); + +private: + void* m_pBuffer; + size_t m_BufferSize; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + SoundInstanceConfig m_SoundInstanceConfig; +#endif + PriorityList m_PriorityList; + PriorityList m_FreeList; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_SoundRuntimeUtility.h b/include/nn/atk/detail/atk_SoundRuntimeUtility.h new file mode 100644 index 0000000..6f3504d --- /dev/null +++ b/include/nn/atk/detail/atk_SoundRuntimeUtility.h @@ -0,0 +1,5 @@ +#pragma once + +namespace nn::atk::detail { +class SoundRuntimeUtility {}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_StartInfoReader.h b/include/nn/atk/detail/atk_StartInfoReader.h new file mode 100644 index 0000000..c84db91 --- /dev/null +++ b/include/nn/atk/detail/atk_StartInfoReader.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class StartInfoReader { +public: + explicit StartInfoReader(const SoundArchive::SoundInfo& soundInfo); + + void Read(const SoundStartable::StartInfo* startInfo); + +private: + SoundStartable::StartInfo::StartOffsetType m_StartOffsetType; + s32 m_StartOffset; + s32 m_DelayTime; + s32 m_DelayCount; + UpdateType m_UpdateType; + s32 m_PlayerPriority; + SoundArchive::ItemId m_PlayerId; + s32 m_ActorPlayerId; + SoundStartable::StartInfo::SequenceSoundInfo* m_pSeqInfo; + SoundStartable::StartInfo::StreamSoundInfo* m_pStrmInfo; + SoundArchive::StreamSoundInfo* m_pStrmMetaInfo; + SoundArchive::StreamSoundInfo2* m_pStrmMetaInfo2; + SoundStartable::StartInfo::WaveSoundInfo* m_pWsdInfo; + s32 m_SubMixIndex; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* m_pOutputReceiver; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(StartInfoReader) == 0x50); +#else +static_assert(sizeof(StartInfoReader) == 0x58); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_ValueArray.h b/include/nn/atk/detail/atk_ValueArray.h new file mode 100644 index 0000000..4c20b6f --- /dev/null +++ b/include/nn/atk/detail/atk_ValueArray.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace nn::atk::detail { +template +class ValueArray { +public: +private: + T* m_pValue; + s32 m_Count; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_VolumeThroughModePacket.h b/include/nn/atk/detail/atk_VolumeThroughModePacket.h new file mode 100644 index 0000000..44641ef --- /dev/null +++ b/include/nn/atk/detail/atk_VolumeThroughModePacket.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class VolumeThroughModePacket { +public: + using VolumeThroughModeArray = ValueArray; + + static size_t GetRequiredMemSize(s32 busCount); + + bool Initialize(void* buffer, size_t size, s32 busCount); + + void Finalize(); + + void Reset(); + + VolumeThroughModePacket& operator=(const VolumeThroughModePacket& rhs); + +private: + VolumeThroughModeArray m_VolumeThroughMode; + bool m_IsVolumeThroughModeUsed; + f32 m_BinaryVolume; +}; +static_assert(sizeof(VolumeThroughModePacket) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_WaveArchiveFile.h b/include/nn/atk/detail/atk_WaveArchiveFile.h new file mode 100644 index 0000000..8e0f684 --- /dev/null +++ b/include/nn/atk/detail/atk_WaveArchiveFile.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct WaveArchiveFile { + constexpr static s32 BlockCount = 2; + + struct InfoBlock; + struct FileBlock; + struct FileHeader : BinaryFileHeader { + + InfoBlock* GetInfoBlock() const; + u32 GetInfoBlockOffset() const; + + FileBlock* GetFileBlock() const; + u32 GetFileBlockOffset() const; + + u32 GetInfoBlockSize() const; + + Util::Reference* GetReferenceBy(u16); + + u32 GetFileBlockSize() const; + + Util::ReferenceWithSize toBlocks[BlockCount]; + }; + static_assert(sizeof(FileHeader) == 0x2C); + + struct FileBlockBody { /* unknown structure */ }; + struct FileBlock { + BinaryBlockHeader header; + FileBlockBody body; + }; + + struct InfoBlockBody { + constexpr static s32 InvalidOffset = -1; + + Util::ReferenceWithSizeTable table; + }; + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_WaveArchiveFileReader.h b/include/nn/atk/detail/atk_WaveArchiveFileReader.h new file mode 100644 index 0000000..e0ee985 --- /dev/null +++ b/include/nn/atk/detail/atk_WaveArchiveFileReader.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class WaveArchiveFileReader { +public: + constexpr static s32 SignatureFile = 0x52415746; // FWAR + constexpr static s32 SignatureWarcTable = 0x54415746; // FWAT + + struct IndividualLoadTable { + void* waveFile[1]; + }; + + WaveArchiveFileReader(); + WaveArchiveFileReader(const void* pWaveArchiveFile, bool isIndividual); + + void Initialize(const void* pWaveArchiveFile, bool isIndividual); + + bool HasIndividualLoadTable() const; + + void Finalize(); + + void InitializeFileTable(); + + u32 GetWaveFileCount() const; + void* GetWaveFile(u32 waveIndex) const; + u32 GetWaveFileSize(u32 waveIndex) const; + u32 GetWaveFileOffsetFromFileHead(u32 waveIndex) const; + + void* SetWaveFile(u32 waveIndex, const void* pWaveFile); + +private: + WaveArchiveFile::FileHeader* m_pHeader; + WaveArchiveFile::InfoBlockBody* m_pInfoBlockBody; + IndividualLoadTable* m_pLoadTable; + bool m_IsInitialized; +}; +static_assert(sizeof(WaveArchiveFileReader) == 0x20); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_WaveFile.h b/include/nn/atk/detail/atk_WaveFile.h new file mode 100644 index 0000000..08dd6f4 --- /dev/null +++ b/include/nn/atk/detail/atk_WaveFile.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct WaveFile { + struct InfoBlock; + struct DataBlock; + struct FileHeader : Util::SoundFileHeader { + + InfoBlock* GetInfoBlock() const; + DataBlock* GetDataBlock() const; + + }; + + struct ChannelInfo; + struct InfoBlockBody { + + ChannelInfo* GetChannelInfo(s32 channelIndex) const; + + u8 encoding; + u8 isLoop; + u8 padding; + u32 sampleRate; + u32 loopStartFrame; + u32 loopEndFrame; + u32 originalLoopStartFrame; + Util::ReferenceTable channelInfoReferenceTable; + }; + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + + struct DspAdpcmInfo { + DspAdpcmParam adpcmParam; + DspAdpcmLoopParam adpcmLoopParam; + }; + static_assert(sizeof(DspAdpcmInfo) == 0x2C); + + struct ChannelInfo { + Util::Reference referToSamples; + Util::Reference referToAdpcmInfo; + u32 reserved; + + void* GetSamplesAddress(const void* dataBlockBodyAddress) const; + DspAdpcmInfo* GetDspAdpcmInfo() const; + }; + static_assert(sizeof(ChannelInfo) == 0x14); + + struct DataBlock { + BinaryBlockHeader header; + union { + s8 pcm8[1]; + s16 pcm16[1]; + u8 byte[1]; + }; + }; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/atk_WaveFileReader.h b/include/nn/atk/detail/atk_WaveFileReader.h new file mode 100644 index 0000000..1987dcf --- /dev/null +++ b/include/nn/atk/detail/atk_WaveFileReader.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class WaveFileReader { +public: + constexpr static s32 SignatureFile = 0x56415746; // FWAV + + static SampleFormat GetSampleFormat(u8 format); + + WaveFileReader(const void* waveFile, s8 waveType); + + bool IsOriginalLoopAvailable() const; + + bool ReadWaveInfo(WaveInfo* info, const void* waveDataOffsetOrigin) const; + + void* GetWaveDataAddress(const WaveFile::ChannelInfo* channelInfo, const void*) const; + +private: + WaveFile::FileHeader* m_pHeader; + WaveFile::InfoBlockBody* m_pInfoBlockBody; + void* m_pDataBlockBody; + DspadpcmReader m_DspadpcmReader; + s8 m_WaveType; +}; +static_assert(sizeof(WaveFileReader) == 0x28); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/debug/atk_Debug.h b/include/nn/atk/detail/debug/atk_Debug.h new file mode 100644 index 0000000..bd90d13 --- /dev/null +++ b/include/nn/atk/detail/debug/atk_Debug.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace nn::atk { +enum DebugWarningFlag { + DebugWarningFlag_NotEnoughInstance, + DebugWarningFlag_NotEnoughSeqsound, + DebugWarningFlag_NotEnoughStrmsound, + DebugWarningFlag_NotEnoughWavesound, + DebugWarningFlag_NotEnoughSeqtrack, + DebugWarningFlag_NotEnoughStrmchannel, +}; + +static u8 gWarningFlag = 0b11111; +static const u32 gWarningBitFlags[6] = {0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000}; + +void Debug_SetWarningFlag(DebugWarningFlag warning, bool); + +namespace detail { +enum DebugSoundType { + DebugSoundType_Seqsound, + DebugSoundType_Strmsound, + DebugSoundType_Wavesound, +}; + +static const char* gSoundTypeStrings[3] = {"seq", "strm", "wave"}; + +bool Debug_GetWarningFlag(DebugWarningFlag warning); +DebugWarningFlag Debug_GetDebugWarningFlagFromSoundType(DebugSoundType type); +char* Debug_GetSoundTypeString(DebugSoundType type); + +using DebugLogFunc = void(*)(char*); + +static DebugLogFunc g_DebugLogHookFunc; +} // namespace nn::atk::detail +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/dsp/atk_BiquadFilterPresets.h b/include/nn/atk/detail/dsp/atk_BiquadFilterPresets.h new file mode 100644 index 0000000..7d0a67c --- /dev/null +++ b/include/nn/atk/detail/dsp/atk_BiquadFilterPresets.h @@ -0,0 +1,128 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class BiquadFilterLpf : BiquadFilterCallback { +public: + constexpr static u32 CoefficientsTableSize = 112; + + static Coefficients CoefficientsTable32000[CoefficientsTableSize]; + + ~BiquadFilterLpf() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterLpf) == 0x8); + +class BiquadFilterHpf : BiquadFilterCallback { +public: + constexpr static u32 CoefficientsTableSize = 97; + + static Coefficients CoefficientsTable32000[CoefficientsTableSize]; + + ~BiquadFilterHpf() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterHpf) == 0x8); + +class BiquadFilterBpf512 : BiquadFilterCallback { +public: + constexpr static u32 CoefficientsTableSize = 122; + + static Coefficients CoefficientsTable32000[CoefficientsTableSize]; + + ~BiquadFilterBpf512() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf512) == 0x8); + +class BiquadFilterBpf1024 : BiquadFilterCallback { +public: + constexpr static u32 CoefficientsTableSize = 93; + + static Coefficients CoefficientsTable32000[CoefficientsTableSize]; + + ~BiquadFilterBpf1024() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf1024) == 0x8); + +class BiquadFilterBpf2048 : BiquadFilterCallback { +public: + constexpr static u32 CoefficientsTableSize = 93; + + static Coefficients CoefficientsTable32000[CoefficientsTableSize]; + + ~BiquadFilterBpf2048() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf2048) == 0x8); + +class BiquadFilterLpfNw4fCompatible48k : BiquadFilterCallback { +public: + static Coefficients CoefficientsTable48000[BiquadFilterLpf::CoefficientsTableSize]; + + ~BiquadFilterLpfNw4fCompatible48k() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterLpfNw4fCompatible48k) == 0x8); + +class BiquadFilterHpfNw4fCompatible48k : BiquadFilterCallback { +public: + static Coefficients CoefficientsTable48000[BiquadFilterHpf::CoefficientsTableSize]; + + ~BiquadFilterHpfNw4fCompatible48k() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterHpfNw4fCompatible48k) == 0x8); + +class BiquadFilterBpf512Nw4fCompatible48k : BiquadFilterCallback { +public: + static Coefficients CoefficientsTable48000[BiquadFilterBpf512::CoefficientsTableSize]; + + ~BiquadFilterBpf512Nw4fCompatible48k() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf512Nw4fCompatible48k) == 0x8); + +class BiquadFilterBpf1024Nw4fCompatible48k : BiquadFilterCallback { +public: + static Coefficients CoefficientsTable48000[BiquadFilterBpf1024::CoefficientsTableSize]; + + ~BiquadFilterBpf1024Nw4fCompatible48k() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf1024Nw4fCompatible48k) == 0x8); + +class BiquadFilterBpf2048Nw4fCompatible48k : BiquadFilterCallback { +public: + static Coefficients CoefficientsTable48000[BiquadFilterBpf2048::CoefficientsTableSize]; + + ~BiquadFilterBpf2048Nw4fCompatible48k() override; + + void GetCoefficients(Coefficients* pOutValue, s32 type, f32 value) override; +}; +static_assert(sizeof(BiquadFilterBpf2048Nw4fCompatible48k) == 0x8); + +namespace driver { +static BiquadFilterLpf BiquadFilterInstanceLpf {}; +static BiquadFilterHpf BiquadFilterInstanceHpf {}; +static BiquadFilterBpf512 BiquadFilterInstanceBpf512 {}; +static BiquadFilterBpf1024 BiquadFilterInstanceBpf1024 {}; +static BiquadFilterBpf2048 BiquadFilterInstanceBpf2048 {}; +static BiquadFilterLpfNw4fCompatible48k BiquadFilterInstanceLpfNw4fCompatible48k {}; +static BiquadFilterHpfNw4fCompatible48k BiquadFilterInstanceHpfNw4fCompatible48k {}; +static BiquadFilterBpf512Nw4fCompatible48k BiquadFilterInstanceBpf512Nw4fCompatible48k {}; +static BiquadFilterBpf1024Nw4fCompatible48k BiquadFilterInstanceBpf1024Nw4fCompatible48k {}; +static BiquadFilterBpf2048Nw4fCompatible48k BiquadFilterInstanceBpf2048Nw4fCompatible48k {}; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/dsp/atk_DspadpcmReader.h b/include/nn/atk/detail/dsp/atk_DspadpcmReader.h new file mode 100644 index 0000000..68bacad --- /dev/null +++ b/include/nn/atk/detail/dsp/atk_DspadpcmReader.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class DspadpcmReader { +public: + DspadpcmReader(); + + bool ReadWaveInfo(WaveInfo* info) const; + +private: + void* m_pDspadpcmData; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/dsp/atk_HardwareManager.h b/include/nn/atk/detail/dsp/atk_HardwareManager.h new file mode 100644 index 0000000..7333546 --- /dev/null +++ b/include/nn/atk/detail/dsp/atk_HardwareManager.h @@ -0,0 +1,276 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace nn::atk::detail::driver { +class HardwareManager { // inherits nn::atk::Util::Singleton +public: + using SubMixList = util::IntrusiveList>; + + constexpr static u32 SoundFrameIntervalMsec = 5; + constexpr static u32 SoundFrameIntervalUsec = 5000; + + constexpr static u32 DefaultRendererSampleRate = 48000; + constexpr static u32 DefaultRendererUserEffectCount = 10; + constexpr static u32 DefaultRendererVoiceCountMax = 96; + + constexpr static u32 DefaultRecordingAudioFrameCount = 8; + + constexpr static u32 AtkVoiceCountMax = 192; + constexpr static u32 MixerCount = 3; + constexpr static u32 ChannelCountMax = 6; + constexpr static u32 BusCount = 4; + + constexpr static u32 DefaultRendererSampleCount = 140; + constexpr static u32 DefaultRendererMixBufferCount = 30; + constexpr static u32 DefaultRendererSubMixCount = 1; + constexpr static u32 DefaultRendererSinkCount = 1; + constexpr static u32 DefaultRendererPerformanceFrameCount = 0; + constexpr static u32 DefaultRendererSystemEffectCount = 4; + + constexpr static u32 SubMixCountMax = 2; + + constexpr static u32 SubMixCountForAdditionalEffect = 1; + constexpr static u32 ChannelCountForAdditionalEffect = 2; + constexpr static u32 AuxBusCountForAdditionalEffect = 2; + constexpr static u32 MixBufferCountForAdditionalEffect = 6; + + constexpr static bool DefaultRendererIsVoiceDropEnabled = false; + + class EffectAuxListScopedLock { + public: + EffectAuxListScopedLock(); + ~EffectAuxListScopedLock(); + }; + void LockEffectAuxList(); + void UnlockEffectAuxList(); + + class EffectAuxListForFinalMixScopedLock { + public: + EffectAuxListForFinalMixScopedLock(); + ~EffectAuxListForFinalMixScopedLock(); + }; + void LockEffectAuxListForFinalMix(); + void UnlockEffectAuxListForFinalMix(); + + class EffectAuxListForAdditionalSubMixScopedLock { + public: + EffectAuxListForAdditionalSubMixScopedLock(); + ~EffectAuxListForAdditionalSubMixScopedLock(); + }; + void LockEffectAuxListForAdditionalSubMix(); + void UnlockEffectAuxListForAdditionalSubMix(); + + class SubMixListScopedLock { + public: + SubMixListScopedLock(); + ~SubMixListScopedLock(); + }; + void LockSubMixList(); + void UnlockSubMixList(); + + class UpdateAudioRendererScopedLock { + public: + UpdateAudioRendererScopedLock(); + ~UpdateAudioRendererScopedLock(); + }; + + class HardwareManagerParameter { + public: + void SetSubMixParameter(bool isStereoModeEnabled, bool isEffectEnabled, + bool isSubMixEnabled, bool isAdditionalEffectBusEnabled, + bool isAdditionalSubMixEnabled, bool isCustomSubMixEnabled, + s32 customSubMixCount, s32 customMixTotalChannelCount); + + private: + s32 m_RendererSampleRate; + s32 m_UserEffectCount; + s32 m_VoiceCount; + s32 m_RecordingAudioFrameCount; + s32 m_SubMixCount; + s32 m_MixBufferCount; + bool m_IsProfilerEnabled; + bool m_IsAdditionalEffectBusEnabled; + bool m_IsAdditionalSubMixEnabled; + bool m_IsEffectEnabled; + bool m_IsRecordingEnabled; + bool m_IsUserCircularBufferSinkEnabled; + bool m_IsPresetSubMixEnabled; + bool m_IsStereoModeEnabled; + bool m_IsSoundThreadEnabled; + bool m_IsVoiceDropEnabled; + bool m_IsCompatibleDownMixSettingEnabled; + bool m_IsPreviousSdkVersionLowPassFilterCompatible; + bool m_IsUnusedEffectChannelMutingEnabled; + bool m_IsCompatibleBusVolumeEnabled; + bool m_IsUserThreadRenderingEnabled; + bool m_IsCustomSubMixEnabled; + bool m_IsMemoryPoolAttachCheckEnabled; + }; + static_assert(sizeof(HardwareManagerParameter) == 0x2c); + + HardwareManager(); + + void ResetParameters(); + + audio::MemoryPoolState GetMemoryPoolState(audio::MemoryPoolType* pPool); + + void SetupAudioRendererParameter(audio::AudioRendererParameter* audioRendererParameter, + const HardwareManagerParameter& hardwareManagerParameter) const; + + size_t GetRequiredMemSize(const HardwareManagerParameter& hardwareManagerParameter) const; + size_t GetRequiredMemSizeForMemoryPool(s32 voiceCount) const; + size_t GetRequiredRecorderWorkBufferSize(const HardwareManagerParameter& hardwareManagerParameter) const; + size_t GetRequiredCircularBufferSinkWithMemoryPoolBufferSize(const HardwareManagerParameter& hardwareManagerParameter) const; + size_t GetRequiredCircularBufferSinkBufferSize(const HardwareManagerParameter& hardwareManagerParameter) const; + + s32 GetChannelCountMax() const; + + bool RegisterRecorder(DeviceOutRecorder* pRecorder); + bool UnregisterRecorder(DeviceOutRecorder* pRecorder); + void UpdateRecorder(); + + u64 ReadRecordingCircularBufferSink(void* buffer, size_t bufferSize); + audio::CircularBufferSinkType* AllocateRecordingCircularBufferSink(); + void FreeRecordingCircularBufferSink(audio::CircularBufferSinkType* circularBufferSink); + void StartRecordingCircularBufferSink(); + + void StopUserCircularBufferSink(); + void StartUserCircularBufferSink(bool isForceStartMode); + u64 ReadUserCircularBufferSink(void* buffer, size_t bufferSize); + + void AttachMemoryPool(audio::MemoryPoolType* pPool, void* buffer, + size_t bufferSize, bool isSoundThreadEnabled); + + Result RequestUpdateAudioRenderer(); + + void DetachMemoryPool(audio::MemoryPoolType* pPool, bool isSoundThreadEnabled); + + void ExecuteAudioRendererRendering(); + + void WaitAudioRendererEvent(); + + s32* GetDroppedLowLevelVoiceCount() const; + + size_t GetRequiredPerformanceFramesBufferSize(HardwareManagerParameter* hardwareManagerParameter); + + Result Initialize(void* buffer, size_t bufferSize, void* memoryPoolBuffer, size_t memoryPoolBufferSize, + void* circularBufferSinkBuffer, size_t circularBufferSinkBufferSize, + HardwareManagerParameter* parameter); + + void SetBiquadFilterCallback(s32, const BiquadFilterCallback* callback); + void SetOutputMode(OutputMode mode,OutputDevice device); + + void UpdateEndUserOutputMode(); + + void Finalize(); + + void Update(); + void UpdateEffect(); + + void SuspendAudioRenderer(); + void ResumeAudioRenderer(); + + bool TimedWaitAudioRendererEvent(TimeSpan timeout); + + void SetAudioRendererRenderingTimeLimit(s32 timeLimit); + s32 GetAudioRendererRenderingTimeLimit(); + + void PrepareReset(); + + bool IsResetReady() const; + + void AddSubMix(SubMix* pSubMix); + void RemoveSubMix(SubMix* pSubMix); + + SubMix* GetSubMix(s32 subMixNumber); + SubMix* GetSubMix(s32 subMixNumber) const; + + s32 GetSubMixCount() const; + s32 GetChannelCount() const; + f32 GetOutputVolume() const; + + void SetOutputDeviceFlag(s32, u8); + + void SetMasterVolume(f32 volume, s32 fadeFrames); + void SetSrcType(SampleRateConverterType sampleRateConverter); + + size_t GetRequiredEffectAuxBufferSize(const EffectAux* pEffect) const; + + void SetAuxBusVolume(AuxBus bus, f32 volume, s32 fadeFrames, s32 subMixIndex); + f32 GetAuxBusVolume(AuxBus bus, s32 subMixIndex) const; + + void SetMainBusChannelVolumeForAdditionalEffect(f32 volume, s32 srcChannel, s32 dstChannel); + f32 GetMainBusChannelVolumeForAdditionalEffect(s32 srcChannel, s32 dstChannel) const; + + void SetAuxBusChannelVolumeForAdditionalEffect(AuxBus bus, f32 volume, s32 srcChannel, s32 dstChannel); + f32 GetAuxBusChannelVolumeForAdditionalEffect(AuxBus bus, s32 srcChannel, s32 dstChannel) const; + + static void FlushDataCache(void* address, size_t length); + +private: + bool m_IsInitialized; + audio::AudioRendererHandle m_RendererHandle; + audio::AudioRendererConfig m_Config; + os::SystemEvent m_SystemEvent; + s32 m_AudioRendererSuspendCount; + std::atomic_ulong m_AudioRendererUpdateCount; + void* m_pAudioRendererWorkBuffer; + void* m_pAudioRendererConfigWorkBuffer; + OutputMode m_OutputMode[1]; + OutputMode m_EndUserOutputMode[1]; + SampleRateConverterType m_SrcType; + MoveValue m_MasterVolume; + MoveValue m_VolumeForReset; + BiquadFilterCallback* m_BiquadFilterCallbackTable[128]; + u8 m_OutputDeviceFlag[32]; + LowLevelVoiceAllocator m_LowLevelVoiceAllocator; + FinalMix m_FinalMix; + SubMix m_SubMix[SubMixCountMax]; + SubMix m_AdditionalSubMix; + SubMixList m_SubMixList; + fnd::CriticalSection m_SubMixListLock; + audio::AudioRendererParameter m_AudioRendererParameter; + audio::DeviceSinkType m_Sink; + MoveValue m_AuxUserVolume[MixerCount]; + MoveValue m_AuxUserVolumeForAdditionalEffect[AuxBusCountForAdditionalEffect]; + bool m_IsInitializedEffect; + bool m_IsPresetSubMixEnabled; + bool m_IsAdditionalEffectEnabled; + bool m_IsAdditionalSubMixEnabled; + bool m_IsStereoModeEnabled; + bool m_IsInitializedSoundThread; + bool m_IsPreviousSdkVersionLowPassFilterCompatible; + bool m_IsMemoryPoolAttachCheckEnabled; + fnd::CriticalSection m_UpdateAudioRendererLock; + fnd::CriticalSection m_UpdateHardwareManagerLock; + fnd::CriticalSection m_EffectAuxListLock; + fnd::CriticalSection m_EffectAuxListForFinalMixLock; + fnd::CriticalSection m_EffectAuxListForAdditionalSubMixLock; + audio::CircularBufferSinkType m_RecordingCircularBufferSink; + CircularBufferSinkState m_RecordingCircularBufferSinkState; + audio::MemoryPoolType m_RecordingCircularBufferSinkMemoryPool; + void* m_RecordingCircularBufferSinkBuffer; + bool m_IsRecordingCircularBufferSinkAllocated; + void* m_RecordingBuffer; + size_t m_RecordingBufferSize; + DeviceOutRecorder* m_pRecorder; + audio::CircularBufferSinkType m_UserCircularBufferSink; + audio::MemoryPoolType m_UserCircularBufferSinkMemoryPool; + void* m_UserCircularBufferSinkBuffer; + size_t m_UserCircularBufferSinkBufferSize; + CircularBufferSinkState m_UserCircularBufferSinkState; + bool m_IsCompatibleBusVolumeEnabled; + bool m_IsUserThreadRenderingEnabled; +}; +static_assert(sizeof(HardwareManager) == 0xa58); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_Bank.h b/include/nn/atk/detail/seq/atk_Bank.h new file mode 100644 index 0000000..d8e5a27 --- /dev/null +++ b/include/nn/atk/detail/seq/atk_Bank.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail::driver { +class Bank { +public: + Bank(); + ~Bank(); + + Channel* NoteOn(const BankFileReader& bankReader, + const WaveArchiveFileReader& warcReader, + const NoteOnInfo& noteOnInfo) const; + + static f32 CalcChannelVelocityVolume(u8 velocity); +}; +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_BankFile.h b/include/nn/atk/detail/seq/atk_BankFile.h new file mode 100644 index 0000000..98dd8ef --- /dev/null +++ b/include/nn/atk/detail/seq/atk_BankFile.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct BankFile { + struct InfoBlock; + struct FileHeader : Util::SoundFileHeader { + + InfoBlock* GetInfoBlock() const; + + }; + + struct Instrument; + struct InfoBlockBody { + + Util::WaveIdTable* GetWaveIdTable() const; + Util::ReferenceTable GetInstrumentReferenceTable() const; + Instrument* GetInstrument(s32 programNo) const; + + Util::Reference toWaveIdTable; + Util::Reference toInstrumentReferenceTable; + }; + static_assert(sizeof(InfoBlockBody) == 0x10); + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + static_assert(sizeof(InfoBlock) == 0x18); + + struct KeyRegion; + struct Instrument { + + KeyRegion* GetKeyRegion(u32 key) const; + + Util::Reference toKeyRegionChunk; + }; + static_assert(sizeof(Instrument) == 0x8); + + struct VelocityRegion; + struct KeyRegion { + + VelocityRegion* GetVelocityRegion(u32 velocity) const; + + Util::Reference toVelocityRegionChunk; + }; + static_assert(sizeof(KeyRegion) == 0x8); + + struct RegionParameter; + struct VelocityRegion { + + u8 GetOriginalKey() const; + u8 GetVolume() const; + u8 GetPan() const; + f32 GetPitch() const ; + bool IsIgnoreNoteOff() const; + u8 GetKeyGroup() const; + u8 GetInterpolationType() const; + AdshrCurve* GetAdshrCurve() const; + RegionParameter* GetRegionParameter() const; + + u32 waveIdTableIndex; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(VelocityRegion) == 0x8); + + struct RegionParameter { + u8 originalKey; + u8 padding1[3]; + u8 volume; + u8 padding2[3]; + u8 pan; + s8 surroundPan; + u8 padding3[2]; + f32 pitch; + bool isIgnoreNoteOff; + u8 keyGroup; + u8 interpolationType; + u8 padding4[1]; + u32 offset; + Util::Reference refToAdshrCurve; + AdshrCurve adshrCurve; + }; + static_assert(sizeof(RegionParameter) == 0x28); +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_BankFileReader.h b/include/nn/atk/detail/seq/atk_BankFileReader.h new file mode 100644 index 0000000..3aeff63 --- /dev/null +++ b/include/nn/atk/detail/seq/atk_BankFileReader.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class BankFileReader { +public: + constexpr static s32 SignatureFile = 0x4b4e4246; // FBNK + + struct VelocityRegionInfo { + u32 waveArchiveId; + u32 waveIndex; + f32 pitch; + AdshrCurve adshrCurve; + u8 originalKey; + u8 volume; + u8 pan; + bool isIgnoreNoteOff; + u8 keyGroup; + u8 interpolationType; + }; + static_assert(sizeof(VelocityRegionInfo) == 0x18); + + BankFileReader(); + explicit BankFileReader(const void* bankFile); + + void Initialize(const void* bankFile); + void Finalize(); + + bool ReadVelocityRegionInfo(VelocityRegionInfo* info, s32 programNo, + s32 key, s32 velocity) const; + + Util::WaveIdTable* GetWaveIdTable() const; + +private: + BankFile::FileHeader* m_pHeader; + BankFile::InfoBlockBody* m_pInfoBlockBody; + bool m_IsInitialized; +}; +static_assert(sizeof(BankFileReader) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_MmlCommand.h b/include/nn/atk/detail/seq/atk_MmlCommand.h new file mode 100644 index 0000000..6a9852c --- /dev/null +++ b/include/nn/atk/detail/seq/atk_MmlCommand.h @@ -0,0 +1,79 @@ +#pragma once + +namespace nn::atk::detail::driver { +class MmlCommand { +public: + enum Mml { + Mml_Wait = 0x80, + Mml_Prg, + + Mml_OpenTrack = 0x88, + Mml_Jump, + Mml_Call, + + Mml_Random = 0xa0, + Mml_Variable, + Mml_If, + Mml_Time, + Mml_TimeRandom, + Mml_TimeVariable, + + Mml_Timebase = 0xb0, + Mml_EnvHold, + Mml_Monophonic, + Mml_VelocityRange, + Mml_BiquadType, + Mml_BiquadValue, + Mml_BankSelect, + + Mml_ModPhase = 0xbd, + Mml_ModCurve, + Mml_FrontBypass, + Mml_Pan, + Mml_Volume, + Mml_MainVolume, + Mml_Transpose, + Mml_PitchBend, + Mml_BendRange, + Mml_Prio, + Mml_NoteWait, + Mml_Tie, + Mml_Porta, + Mml_ModDepth, + Mml_ModSpeed, + Mml_ModType, + Mml_ModRange, + Mml_PortaSw, + Mml_PortaTime, + Mml_Attack, + Mml_Decay, + Mml_Sustain, + Mml_Release, + Mml_LoopStart, + Mml_Volume2, + Mml_Printvar, + Mml_SurroundPan, + Mml_LpfCutoff, + Mml_FxsendA, + Mml_FxsendB, + Mml_Mainsend, + Mml_InitPan, + Mml_Mute, + Mml_FxsendC, + Mml_Damper, + Mml_ModDelay, + Mml_Tempo, + + Mml_SweepPitch = 0xe3, + Mml_ModPeriod, + + Mml_ExCommand = 0xf0, + + Mml_EnvReset = 0xfb, + Mml_LoopEnd, + Mml_Ret, + Mml_AllocTrack, + Mml_Fin, + }; +}; +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_MmlParser.h b/include/nn/atk/detail/seq/atk_MmlParser.h new file mode 100644 index 0000000..62f369f --- /dev/null +++ b/include/nn/atk/detail/seq/atk_MmlParser.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class MmlParser { +public: + enum SeqArgType { + SeqArgType_None, + SeqArgType_U8, + SeqArgType_S16, + SeqArgType_Vmidi, + SeqArgType_Random, + SeqArgType_Variable, + }; + + constexpr static u32 PanCenter = 64; + constexpr static u32 SurroundPanCenter = PanCenter; + + constexpr static u32 TempoMin = 0; + constexpr static u32 TempoMax = 1023; + + MmlParser(); + virtual ~MmlParser(); + + SequenceTrack::ParseResult Parse(MmlSequenceTrack* track, bool doNoteOn) const; + + s32 ReadArg(const u8** ptr, SequenceSoundPlayer* player, SequenceTrack* track, + SeqArgType argType) const; + + s32 Read24(const u8** ptr) const; + s16 Read16(const u8** ptr) const; + + void CommandProc(MmlSequenceTrack* track, u32 command, s32 commandArg1, s32 commandArg2) const; + + s16* GetVariablePtr(SequenceSoundPlayer* player, SequenceTrack* track, s32 varNo) const; + + void NoteOnCommandProc(MmlSequenceTrack* track, s32 key, s32 velocity, s32 length, bool tieFlag) const; + + s16 ReadVar(const u8** ptr) const; + + static u32 ParseAllocTrack(const void* baseAddress, u32 seqOffset, u32* allocTrack); + +private: + static bool* mPrintVarEnabledFlag; +}; +static_assert(sizeof(MmlParser) == 0x8); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_MmlSequenceTrack.h b/include/nn/atk/detail/seq/atk_MmlSequenceTrack.h new file mode 100644 index 0000000..5b1c66c --- /dev/null +++ b/include/nn/atk/detail/seq/atk_MmlSequenceTrack.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class MmlParser; +class MmlSequenceTrack : SequenceTrack { +public: + MmlSequenceTrack(); + ~MmlSequenceTrack() override; + + ParseResult Parse(bool doNoteOn) override; + +private: + MmlParser* m_pParser; +}; +static_assert(sizeof(MmlSequenceTrack) == 0x1f0); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_MmlSequenceTrackAllocator.h b/include/nn/atk/detail/seq/atk_MmlSequenceTrackAllocator.h new file mode 100644 index 0000000..468ebda --- /dev/null +++ b/include/nn/atk/detail/seq/atk_MmlSequenceTrackAllocator.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail::driver { +class MmlSequenceTrackAllocator : SequenceTrackAllocator { +public: + using MmlSequenceTrackPool = InstancePool; + + SequenceTrack* AllocTrack(SequenceSoundPlayer* player) override; + + void FreeTrack(SequenceTrack* track); + + s32 Create(void* buffer, size_t size); + + void Destroy(); + + s32 GetAllocatableTrackCount(); + +private: + MmlParser* m_pParser; + MmlSequenceTrackPool m_TrackPool; +}; +static_assert(sizeof(MmlSequenceTrackAllocator) == 0x28); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceSound.h b/include/nn/atk/detail/seq/atk_SequenceSound.h new file mode 100644 index 0000000..405cf9c --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceSound.h @@ -0,0 +1,113 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class SequenceSound; +using SequenceSoundInstanceManager = SoundInstanceManager; + +class SequenceSound : BasicSound { +public: + constexpr static u32 BankIndexMin = 0; + constexpr static u32 BankIndexMax = 3; + + constexpr static u8 TransposeMin = 192; + constexpr static u8 TransposeMax = 63; + + constexpr static u8 VelocityRangeMin = 0; + constexpr static u32 VelocityRangeMax = 0x7f00; + + struct Resource { + void* seq; + void* banks[4]; + void* warcs[4]; + bool warcIsIndividuals[4]; + }; + static_assert(sizeof(Resource) == 0x50); + + explicit SequenceSound(SequenceSoundInstanceManager& manager); + ~SequenceSound() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void Setup(driver::SequenceTrackAllocator* trackAllocator, u32 allocTracks, + driver::NoteOnCallback* noteOnCallback, s32 channelPriority, + bool isReleasePriorityFix, SequenceUserProcCallback userproc, void* userprocArg); + + void Prepare(const Resource& res, const driver::SequenceSoundPlayer::StartInfo& startInfo); + + void Skip(driver::SequenceSoundPlayer::StartOffsetType, s32); + + void SetTempoRatio(f32 tempoRatio); + + void SetChannelPriority(s32 priority); + void OnUpdatePlayerPriority() override; + + void SetTrackMute(u32 trackBitFlag, SequenceMute mute); + void SetTrackMute(u32 trackBitFlag, bool); + void SetTrackSilence(u32 trackBitFlag, bool, s32); + void SetTrackVolume(u32 trackBitFlag, f32 volume); + void SetTrackPitch(u32 trackBitFlag, f32 pitch); + void SetTrackMainOutVolume(u32 trackBitFlag, f32 volume); + void SetTrackChannelMixParameter(u32 trackBitFlag, u32 srcChNo, const MixParameter& param); + void SetTrackPan(u32 trackBitFlag, f32 pan); + void SetTrackSurroundPan(u32 trackBitFlag, f32 surroundPan); + void SetTrackMainSend(u32 trackBitFlag, f32 send); + void SetTrackFxSend(u32 trackBitFlag, AuxBus bus, f32 send); + void SetTrackLpfFreq(u32 trackBitFlag, f32 lpfFreq); + void SetTrackBiquadFilter(u32 trackBitFlag, s32 type, f32 value); + void SetTrackBankIndex(u32 trackBitFlag, s32 bankIndex); + void SetTrackTranspose(u32 trackBitFlag, s8 transpose); + void SetTrackVelocityRange(u32 trackBitFlag, u8 range); + + void SetTrackOutputLine(u32 trackBitFlag, u32 outputLine); + void ResetTrackOutputLine(u32 trackBitFlag); + + bool ReadVariable(s32 varNo, s16* varPtr) const; + static bool ReadGlobalVariable(s32 varNo, s16* varPtr); + bool ReadTrackVariable(s32, s32, s16*) const; + + void WriteVariable(s32 varNo, s16 var); + static void WriteGlobalVariable(s32 varNo, s16 var); + void WriteTrackVariable(s32, s32, s16 var); + + u64 GetTick() const; + + bool IsAttachedTempSpecialHandle() override; + void DetachTempSpecialHandle() override; + + void RegisterDataLoadTask(const driver::SequenceSoundLoader::LoadInfo& loadInfo, + const driver::SequenceSoundPlayer::StartInfo& startInfo); + + bool IsPrepared() const override; + + driver::BasicSoundPlayer* GetBasicSoundPlayerHandle() override; + + void OnUpdateParam() override; + + +private: + friend SequenceSoundInstanceManager; + + util::IntrusiveListNode m_PriorityLink; + SequenceSoundHandle* m_pTempSpecialHandle; + SequenceSoundInstanceManager* m_Manager; + bool m_InitializeFlag; + bool m_CanUseTask; + bool m_IsCalledPrepare; + u8 m_Padding[1]; + driver::SequenceSoundPlayer m_PlayerInstance; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SequenceSound) == 0x570); +#else +static_assert(sizeof(SequenceSound) == 0x5a0); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceSoundFile.h b/include/nn/atk/detail/seq/atk_SequenceSoundFile.h new file mode 100644 index 0000000..d93969f --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceSoundFile.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct SequenceSoundFile { + struct DataBlock; + struct LabelBlock; + struct FileHeader : Util::SoundFileHeader { + + DataBlock* GetDataBlock() const; + LabelBlock* GetLabelBlock() const; + }; + + struct LabelInfo { + Util::Reference referToSequenceData; + u32 labelStringLength; + char label[1]; + }; + + struct LabelBlockBody { + + LabelInfo* GetLabelInfo(s32 index) const; + char* GetLabel(s32 index) const; + char* GetLabelByOffest(s32 labelOffset) const; + + u32 GetOffset(s32 index, u32* offsetPtr) const; + bool GetOffsetByLabel(char* label, u32* offsetPtr) const; + + Util::ReferenceTable labelInfoReferenceTable; + }; + + struct LabelBlock { + BinaryBlockHeader header; + LabelBlockBody body; + }; + + struct DataBlockBody { + u8 sequenceData[1]; + }; + + struct DataBlock { + BinaryBlockHeader header; + DataBlockBody body; + }; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceSoundFileReader.h b/include/nn/atk/detail/seq/atk_SequenceSoundFileReader.h new file mode 100644 index 0000000..9a06069 --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceSoundFileReader.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class SequenceSoundFileReader { +public: + constexpr static s32 SignatureFile = 0x51455346; // FSEQ + + explicit SequenceSoundFileReader(void* sequenceFile); + + void* GetSequenceData(); + + bool GetOffsetByLabel(const char* label, u32* offsetPtr) const; + bool GetLabelByOffset(u32 offset) const; + +private: + SequenceSoundFile::FileHeader* m_pHeader; + SequenceSoundFile::DataBlockBody* m_pDataBlockBody; + SequenceSoundFile::LabelBlockBody* m_pLabelBlockBody; +}; +static_assert(sizeof(SequenceSoundFileReader) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceSoundPlayer.h b/include/nn/atk/detail/seq/atk_SequenceSoundPlayer.h new file mode 100644 index 0000000..51b7290 --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceSoundPlayer.h @@ -0,0 +1,318 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nn::atk { +struct SequenceUserProcCallbackParam { + s16* localVariable; + s16* globalVariable; + s16* trackVariable; + bool cmpFlag; +}; +static_assert(sizeof(SequenceUserProcCallbackParam) == 0x20); + +using SequenceUserProcCallback = void(*)(u16,SequenceUserProcCallbackParam*,void*); + +namespace detail::driver { +class SequenceSoundLoader; +using SequenceSoundLoaderManager = LoaderManager; + +class SequenceSoundLoader { +public: + struct LoadInfo { + LoadInfo(const SoundArchive* arc, const SoundDataManager* mgr, + LoadItemInfo* seq, LoadItemInfo* banks, SoundPlayer* player); + + SoundArchive* soundArchive; + SoundDataManager* soundDataManager; + LoadItemInfo* loadInfoSeq; + LoadItemInfo* loadInfoBanks[4]; + SoundPlayer* soundPlayer; + }; + static_assert(sizeof(LoadInfo) == 0x40); + + struct Arg { + SoundArchive* soundArchive; + SoundDataManager* soundDataManager; + SoundPlayer* soundPlayer; + LoadItemInfo loadInfoSeq; + LoadItemInfo loadInfoBanks[4]; + }; + static_assert(sizeof(Arg) == 0x68); + + struct Data { + void* seqFile; + void* bankFiles[4]; + void* warcFiles[4]; + bool warcIsIndividuals[4]; + }; + static_assert(sizeof(Data) == 0x50); + + class DataLoadTask : Task { + public: + DataLoadTask(); + ~DataLoadTask() override; + + void Initialize(); + + bool TryAllocPlayerHeap(); + + void Execute(TaskProfileLogger& logger) override; + + private: + Arg m_Arg; + Data m_Data; + PlayerHeap* m_pPlayerHeap; + PlayerHeapDataManager* m_pPlayerHeapDataManager; + bool m_IsLoadSuccess; + u8 m_Padding[3]; + }; + static_assert(sizeof(DataLoadTask) == 0x118); + + class FreePlayerHeapTask : Task { + public: + FreePlayerHeapTask(); + ~FreePlayerHeapTask() override; + + void Initialize(); + void Execute(TaskProfileLogger& logger) override; + + private: + Arg m_Arg; + PlayerHeap* m_pPlayerHeap; + PlayerHeapDataManager* m_pPlayerHeapDataManager; + }; + static_assert(sizeof(FreePlayerHeapTask) == 0xc0); + + ~SequenceSoundLoader(); + + void Initialize(const Arg& arg); + + void Finalize(); + + bool IsInUse(); + + bool TryWait(); + +private: + friend SequenceSoundLoaderManager; + + DataLoadTask m_Task; + FreePlayerHeapTask m_FreePlayerHeapTask; + PlayerHeapDataManager m_PlayerHeapDataManager; + util::IntrusiveListNode m_LinkForLoaderManager; +}; +static_assert(sizeof(SequenceSoundLoader) == 0x4b0); + +class SequenceSoundPlayer : BasicSoundPlayer, DisposeCallback, SoundThread::PlayerCallback { +public: + enum StartOffsetType { + StartOffsetType_Tick, + StartOffsetType_Millisec, + }; + + enum ResState { + ResState_Invalid, + ResState_RecvLoadReq, + ResState_AppendLoadTask, + ResState_Assigned, + }; + + constexpr static s32 PlayerVariableCount = 16; + constexpr static s32 GlobalVariableCount = 16; + constexpr static s32 TrackCountPerPlayer = 16; + + constexpr static u32 AllTrackBitFlag = 0x0000FFFF; + + constexpr static s32 VariableDefaultValue = -1; + + constexpr static s32 DefaultTimebase = 48; + constexpr static s32 DefaultTempo = 120; + constexpr static u32 DefaultSkipIntervalTick = 16 * DefaultTimebase; + + struct ParserPlayerParam { + u8 priority; + u8 timebase; + u16 tempo; + MoveValue volume; + NoteOnCallback* callback; + }; + static_assert(sizeof(ParserPlayerParam) == 0x18); + + struct StartInfo { + s32 seqOffset; + StartOffsetType startOffsetType; + s32 startOffset; + s32 delayTime; + s32 delayCount; + UpdateType updateType; + }; + static_assert(sizeof(StartInfo) == 0x18); + + struct PrepareArg { + void* seqFile; + void* bankFiles[4]; + void* warcFiles[4]; + bool warcIsIndividuals[4]; + s32 seqOffset; + s32 delayTime; + s32 delayCount; + UpdateType updateType; + }; + static_assert(sizeof(PrepareArg) == 0x60); + + struct SetupArg { + SequenceTrackAllocator* trackAllocator; + u32 allocTracks; + NoteOnCallback* callback; + }; + static_assert(sizeof(SetupArg) == 0x18); + + static void InitSequenceSoundPlayer(); + + SequenceSoundPlayer(); + ~SequenceSoundPlayer() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void FinishPlayer(); + + void FreeLoader(); + + void Setup(const SetupArg& arg); + + void SetPlayerTrack(s32 trackNo, SequenceTrack* track); + + void ForceTrackMute(u32); + + SequenceTrack* GetPlayerTrack(s32 trackNo); + + void Start() override; + void Stop() override; + void Pause(bool flag) override; + void Skip(StartOffsetType offsetType, s32 offset); + + void SetTempoRatio(f32 tempoRatio); + void SetPanRange(f32 panRange); + void SetChannelPriority(s32 priority); + void SetReleasePriorityFix(bool fix); + void SetSequenceUserprocCallback(SequenceUserProcCallback callback, void* arg); + + void CallSequenceUserprocCallback(u16 procId, SequenceTrack* track); + + s16* GetVariablePtr(s32 varNo); + + void GetLocalVariable(s32 varNo) const; + static s16 GetGlobalVariable(s32 varNo); + + void SetLocalVariable(s32 varNo, s16 var); + static void SetGlobalVariable(s32 varNo, s16 var); + + void SetTrackMute(u32 trackBitFlag, SequenceMute mute); + void SetTrackSilence(u64 trackBitFlag, bool silenceFlag, s32 fadeTimes); + void SetTrackVolume(u32 trackBitFlag, f32 volume); + void SetTrackPitch(u32 trackBitFlag, f32 pitch); + void SetTrackLpfFreq(u32 trackBitFlag, f32 lpfFreq); + void SetTrackBiquadFilter(u32 trackBitFlag, s32 type, f32 value); + bool SetTrackBankIndex(u32 trackBitFlag, s32 bankIndex); + void SetTrackTranspose(u32 trackBitFlag, s8 transpose); + void SetTrackVelocityRange(u32 trackBitFlag, u8 range); + + void SetTrackOutputLine(u32 trackBitFlag, u32 outputLine); + void ResetTrackOutputLine(u32 trackBitFlag); + + void SetTrackTvVolume(u32 trackBitFlag, f32 volume); + void SetTrackChannelTvMixParameter(u32 trackBitFlag, u32 srcChNo, const MixParameter& param); + void SetTrackTvPan(u32 trackBitFlag, f32 pan); + void SetTrackTvSurroundPan(u32 trackBitFlag, f32 surroundPan); + void SetTrackTvMainSend(u32 trackBitFlag, f32 send); + void SetTrackTvFxSend(u32 trackBitFlag, AuxBus bus, f32 send); + + void InvalidateData(const void* start, const void* end) override; + + SequenceTrack* GetPlayerTrack(s32 trackNo) const; + void CloseTrack(s32 trackNo); + + void UpdateChannelParam(); + + s32 ParseNextTick(bool doNoteOn); + + void Update(); + + bool TryAllocLoader(); + + void PrepareForPlayerHeap(PrepareArg* arg); + + void SkipTick(); + void UpdateTick(); + + Channel* NoteOn(u8 bankIndex, const NoteOnInfo& noteOnInfo); + + void Prepare(const PrepareArg& arg); + + void RequestLoad(const StartInfo& info, const SequenceSoundLoader::Arg& arg); + + u64 GetProcessTick(const SoundProfile&); + + void PrepareForMidi(const void**, const void**, bool*); + + static void SetSkipIntervalTick(s32); + static s32 GetSkipIntervalTick(); + + void ChannelCallback(Channel* channel); + + void OnUpdateFrameSoundThread() override; + void OnUpdateFrameSoundThreadWithAudioFrameFrequency() override; + void OnShutdownSoundThread() override; + +private: + bool m_ReleasePriorityFixFlag; + bool m_IsPrepared; + f32 m_PanRange; + f32 m_TempoRatio; + f32 m_TickFraction; + u32 m_SkipTickCounter; + f32 m_SkipTimeCounter; + s32 m_DelayCount; + ParserPlayerParam m_ParserParam; + SequenceTrackAllocator* m_pSequenceTrackAllocator; + SequenceUserProcCallback m_SequenceUserprocCallback; + void* m_pSequenceUserprocCallbackArg; + SequenceTrack* m_pTracks[TrackCountPerPlayer]; + s16 m_LocalVariable[PlayerVariableCount]; + u32 m_TickCounter; + WaveArchiveFileReader m_WarcFileReader[4]; + BankFileReader m_BankFileReader[4]; + u8 m_ResState; + bool m_IsInitialized; + bool m_IsRegisterPlayerCallback; + u8 m_Padding[1]; + StartInfo m_StartInfo; + SequenceSoundLoaderManager* m_pLoaderManager; + SequenceSoundLoader* m_pLoader; + SequenceSoundLoader::Arg m_LoaderArg; + UpdateType m_UpdateType; + + static s16 m_GlobalVariable[GlobalVariableCount]; + static s32 m_SkipIntervalTickPerFrame; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SequenceSoundPlayer) == 0x358); +#else +static_assert(sizeof(SequenceSoundPlayer) == 0x368); +#endif +} // namespace nn::atk::detail::driver +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceSoundRuntime.h b/include/nn/atk/detail/seq/atk_SequenceSoundRuntime.h new file mode 100644 index 0000000..a947bef --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceSoundRuntime.h @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nn::atk::detail { +class SequenceSoundRuntime { +public: + class SequenceNoteOnCallback : driver::NoteOnCallback { + public: + ~SequenceNoteOnCallback() override; + + driver::Channel* NoteOn(driver::SequenceSoundPlayer* seqPlayer, u8 bankIndex, + const driver::NoteOnInfo& noteOnInfo) override; + private: + SequenceSoundRuntime* m_pSequenceSoundRuntime; + }; + static_assert(sizeof(SequenceNoteOnCallback) == 0x10); + + struct PrepareContext { + SequenceSoundFile* pSequenceSoundFile; + u32 sequenceOffset; + u32 allocateTrackFlags; + LoadItemInfo loadTargetSequenceInfo; + LoadItemInfo loadTargetBankInfos[4]; + LoadItemInfo loadTargetWaveArchiveInfos[4]; + bool isLoadIndividuals[4]; + bool canUsePlayerHeap; + bool isRegisterDataLoadTaskNeeded; + }; + static_assert(sizeof(PrepareContext) == 0xa8); + + SequenceSoundRuntime(); + ~SequenceSoundRuntime(); + + bool Initialize(s32 soundCount, void** pOutAllocatedAddr, const void* endAddr); + void Finalize(); + + void SetupSequenceTrack(s32 trackCount, void** pOutAllocatedAddr, const void* endAddr); + void SetupUserParam(void** pOutAllocatedAddr, size_t adjustSize); + + static size_t GetRequiredMemorySize(const SoundArchive::SoundArchivePlayerInfo& soundArchivePlayerInfo, + s32 alignment); + static size_t GetRequiredSequenceTrackMemorySize(const SoundArchive::SoundArchivePlayerInfo& soundArchivePlayerInfo, + s32 alignment); + + bool IsSoundArchiveAvailable() const; + + s32 GetActiveCount() const; + s32 GetFreeCount() const; + + static void SetSequenceSkipIntervalTick(s32 tick); + static s32 GetSequenceSkipIntervalTick(); + + void Update(); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + SequenceSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo); +#else + SequenceSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo, OutputReceiver* pOutputReceiver); +#endif + + SoundStartable::StartResult PrepareImpl(const SoundArchiveManager::SnapShot& snapShot, + SoundArchive::ItemId soundId, + SequenceSound* sound, + const SoundArchive::SoundInfo* commonInfo, + const StartInfoReader& startInfoReader); + + SoundStartable::StartResult SetupSequenceSoundInfo(SoundStartable::StartInfo::SequenceSoundInfo* sequenceSoundInfo, + SoundArchive::ItemId soundId, + const SoundArchive& soundArchive, + const SoundStartable::StartInfo::SequenceSoundInfo* pExternalSequenceSoundInfo); + + SoundStartable::StartResult SetupSequenceSoundFile(PrepareContext* pOutContext, + const SequenceSound& sound, + const SoundArchive& soundArchive, + const SoundDataManager& soundDataManager, + const SoundArchive::SoundInfo& commonInfo, + const SoundStartable::StartInfo::SequenceSoundInfo* pExternalSequenceSoundInfo); + + SoundStartable::StartResult SetupBankFileAndWaveArchiveFile(PrepareContext* pOutContext, + const SequenceSound& sound, + const SoundStartable::StartInfo::SequenceSoundInfo& sequenceSoundInfo, + const SoundArchiveManager::SnapShot& snapShot, + const SoundStartable::StartInfo::SequenceSoundInfo* pExternalSequenceSoundInfo); + + void SetupSequenceSoundPlayerStartInfo(SoundStartable::StartInfo* startInfo, + SoundArchive::ItemId soundId, + const StartInfoReader& startInfoReader); + + void DumpMemory(const SoundArchive*) const; + + void SetupBankFileAndWaveArchiveFileFromHook(PrepareContext* pOutContext, + SequenceSound* sound, + SoundArchive* soundArchive); + + +private: + SequenceSoundInstanceManager m_SequenceSoundInstanceManager; + driver::SequenceSoundLoaderManager m_SequenceSoundLoaderManager; + driver::SequenceTrackAllocator* m_pSequenceTrackAllocator; + driver::MmlSequenceTrackAllocator m_MmlSequenceTrackAllocator; + driver::MmlParser m_MmlParser; + SequenceNoteOnCallback m_SequenceCallback; + SequenceUserProcCallback m_SequenceUserProcCallback; + void* m_pSequenceUserProcCallbackArg; + SoundArchiveManager* m_pSoundArchiveManager; + SoundArchiveFilesHook* m_pSoundArchiveFilesHook; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SequenceSoundRuntime) == 0xe0); +#else +static_assert(sizeof(SequenceSoundRuntime) == 0xe8); +#endif +} // namespace nn::atk::detail diff --git a/include/nn/atk/detail/seq/atk_SequenceTrack.h b/include/nn/atk/detail/seq/atk_SequenceTrack.h new file mode 100644 index 0000000..230020c --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceTrack.h @@ -0,0 +1,155 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class SequenceSoundPlayer; + +class SequenceTrack { +public: + enum ParseResult { + ParseResult_Continue, + ParseResult_Finish, + }; + + constexpr static u32 CallStackDepth = 10; + + constexpr static u32 DefaultPriority = 64; + constexpr static u32 DefaultBendRange = 2; + constexpr static u32 DefaultPortaKey = 60; + + constexpr static s32 InvalidEnvelope = 255; + constexpr static s32 MaxEnvelopeValue = 127; + + constexpr static s32 ParserParamSize = 32; + + constexpr static s32 TrackVariableCount = 16; + + constexpr static s32 PauseReleaseValue = 16; + constexpr static s32 MuteReleaseValue = 127; + + + struct ParserTrackParam { + struct CallStack { + u8 loopFlag; + u8 loopCount; + u8 padding[2]; + u8* address; + }; + static_assert(sizeof(CallStack) == 0x10); + + u8* baseAddr; + u8* currentAddr; + bool cmpFlag; + bool noteWaitFlag; + bool tieFlag; + bool monophonicFlag; + CallStack callStack[CallStackDepth]; + u8 callStackDepth; + bool frontBypassFlag; + bool muteFlag; + bool silenceFlag; + s32 wait; + bool noteFinishWait; + bool portaFlag; + bool damperFlag; + u8 bankIndex; + s32 prgNo; + f32 sweepPitch; + MoveValue volume; + MoveValue volume2; + MoveValue pan; + MoveValue surroundPan; + MoveValue pitchBend; + CurveLfoParam lfoParam[4]; + u8 lfoTarget[4]; + u8 velocityRange; + u8 bendRange; + s8 initPan; + u8 padding1[1]; + s8 transpose; + u8 priority; + u8 portaKey; + u8 portaTime; + u8 attack; + u8 decay; + u8 sustain; + u8 release; + s16 envHold; + s8 biquadType; + u8 mainSend; + u8 fxSend[3]; + u8 padding2[1]; + f32 lpfFreq; + f32 biquadValue; + s32 outputLine; + }; + static_assert(sizeof(ParserTrackParam) == 0x150); + + virtual ~SequenceTrack(); + virtual ParseResult Parse(bool doNoteOn) = 0; + + SequenceTrack(); + + void SetPlayerTrackNo(s32 playerTrackNo); + + void InitParam(); + + void Close(); + + void SetSeqData(const void* seqBase, s32 seqOffset); + + void Open(); + + void ReleaseAllChannel(s32 release); + void FreeAllChannel(); + + void UpdateChannelLength(); + void UpdateChannelRelease(Channel*); + + s32 ParseNextTick(bool doNoteOn); + + void StopAllChannel(); + void UpdateChannelParam(); + void PauseAllChannel(bool flag); + + void AddChannel(Channel*); + + s32 GetChannelCount() const; + + static void ChannelCallbackFunc(Channel* dropChannel, + Channel::ChannelCallbackStatus callbackStatus, void* userData); + + void SetMute(SequenceMute mute); + void ForceMute(); + + void SetSilence(bool silenceFlag, s32 fadeTimes); + void SetBiquadFilter(s32 type, f32 value); + void SetBankIndex(s32 bankIndex); + void SetTranspose(s8 transpose); + void SetVelocityRange(u8 range); + void SetOutputLine(s32 outputLine); + void SetTvMixParameter(u32 srcChNo, s32 mixChNo, f32 param); + + s16 GetTrackVariable(s32 varNo) const; + void SetTrackVariable(s32 varNo, s16 var); + + s16* GetVariablePtr(s32 varNo); + + Channel* NoteOn(s32 key, s32 velocity, s32 length, bool tieFlag); + +private: + u8 m_PlayerTrackNo; + bool m_OpenFlag; + bool m_ForceMute; + f32 m_ExtVolume; + f32 m_ExtPitch; + f32 m_PanRange; + OutputParam m_TvParam; + ParserTrackParam m_ParserTrackParam; + s16 m_TrackVariable[TrackVariableCount]; + SequenceSoundPlayer* m_pSequenceSoundPlayer; + Channel* m_pChannelList; +}; +static_assert(sizeof(SequenceTrack) == 0x1e8); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/seq/atk_SequenceTrackAllocator.h b/include/nn/atk/detail/seq/atk_SequenceTrackAllocator.h new file mode 100644 index 0000000..91ad028 --- /dev/null +++ b/include/nn/atk/detail/seq/atk_SequenceTrackAllocator.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class SequenceSoundPlayer; + +class SequenceTrackAllocator { +public: + virtual ~SequenceTrackAllocator() = default; + virtual SequenceTrack* AllocTrack(SequenceSoundPlayer* player) = 0; +}; +static_assert(sizeof(SequenceTrackAllocator) == 0x8); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamBufferPool.h b/include/nn/atk/detail/strm/atk_StreamBufferPool.h new file mode 100644 index 0000000..e22a8cb --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamBufferPool.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class StreamBufferPool { +public: + constexpr static u32 BlockMax = 32; + constexpr static u8 BitPerByte = 8; + + void Initialize(void* buffer, size_t size, s32 blockCount); + void Finalize(); + + void* Alloc(); + void Free(void* pPtr); + +private: + void* m_Buffer; + size_t m_BufferSize; + size_t m_BlockSize; + s32 m_BlockCount; + s32 m_AllocCount; + u8 m_AllocFlags[BlockMax / BitPerByte]; +}; +static_assert(sizeof(StreamBufferPool) == 0x28); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSound.h b/include/nn/atk/detail/strm/atk_StreamSound.h new file mode 100644 index 0000000..ac15a7f --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSound.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class StreamSound; +using StreamSoundInstanceManager = SoundInstanceManager; + +class StreamSound : BasicSound { +public: + explicit StreamSound(const StreamSoundInstanceManager& manager); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void Setup(const driver::StreamSoundPlayer::SetupArg& arg); + + void Prepare(const driver::StreamSoundPlayer::PrepareBaseArg& arg); + void PreparePrefetch(const void* strmPrefetchFile, + const driver::StreamSoundPlayer::PrepareBaseArg& arg); + + void UpdateMoveValue() override; + + void OnUpdateParam() override; + + void SetTrackVolume(u32 trackBitFlag, f32 volume, s32); + void SetTrackInitialVolume(u32 trackBitFlag, u32 volume); + + void SetTrackOutputLine(u32 trackBitFlag, u32 outputLine); + void ResetTrackOutputLine(u32 trackBitFlag); + + void SetTrackMainOutVolume(u32 trackBitFlag, f32 volume); + void SetTrackChannelMixParameter(u32 trackBitFlag, u32 srcChNo, const MixParameter& param); + void SetTrackPan(u32 trackBitFlag, f32 pan); + void SetTrackSurroundPan(u32 trackBitFlag, f32 span); + void SetTrackMainSend(u32 trackBitFlag, f32 send); + void SetTrackFxSend(u32 trackBitFlag, AuxBus bus, f32 send); + + void OnUpdatePlayerPriority() override; + + bool IsAttachedTempSpecialHandle() override; + void DetachTempSpecialHandle() override; + + bool ReadStreamDataInfo(StreamDataInfo*) const; + + s32 GetPlayLoopCount() const; + position_t GetPlaySamplePosition(bool) const; + f32 GetFilledBufferPercentage() const; + s32 GetBufferBlockCount(WaveBuffer::Status waveBufferStatus) const; + s32 GetTotalBufferBlockCount() const; + + bool IsPrepared() const override; + bool IsSuspendByLoadingDelay() const; + bool IsLoadingDelayState() const; + + driver::BasicSoundPlayer * GetBasicSoundPlayerHandle() override; + +private: + friend StreamSoundInstanceManager; + + util::IntrusiveListNode m_PriorityLink; + StreamSoundHandle* m_pTempSpecialHandle; + StreamSoundInstanceManager* m_Manager; + MoveValue m_TrackVolume[8]; + u16 m_AllocTrackFlag; + bool m_InitializeFlag; + u8 m_Padding[1]; + u32 m_AvailableTrackBitFlag[2]; + void* m_pCacheBuffer; + size_t m_CacheSize; + driver::StreamSoundPlayer m_PlayerInstance; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(StreamSound) == 0x11a00); +#else +static_assert(sizeof(StreamSound) == 0x11a40); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundFile.h b/include/nn/atk/detail/strm/atk_StreamSoundFile.h new file mode 100644 index 0000000..f43d87a --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundFile.h @@ -0,0 +1,132 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class StreamSoundFile { +public: + struct FileHeader : BinaryFileHeader { + + constexpr static u8 BlockCount = 4; + + Util::Reference* GetReferenceBy(u16) const; + + bool HasSeekBlock() const; + bool HasRegionBlock() const; + + u32 GetInfoBlockSize() const; + u32 GetSeekBlockSize() const; + u32 GetDataBlockSize() const; + u32 GetRegionBlockSize() const; + + u32 GetInfoBlockOffset() const; + u32 GetSeekBlockOffset() const; + u32 GetDataBlockOffset() const; + u32 GetRegionBlockOffset() const; + + Util::ReferenceWithSize toBlocks[BlockCount]; + }; + static_assert(sizeof(FileHeader) == 0x44); + + struct StreamSoundInfo { + u8 encodeMethod; + bool isLoop; + u8 channelCount; + u8 regionCount; + u32 sampleRate; + u32 loopStart; + u32 frameCount; + u32 blockCount; + u32 oneBlockBytes; + u32 oneBlockSamples; + u32 lastBlockBytes; + u32 lastBlockSamples; + u32 lastBlockPaddedBytes; + u32 sizeofSeekInfoAtom; + u32 seekInfoIntervalSamples; + Util::Reference sampleDataOffset; + u16 regionInfoBytes; + u8 padding[2]; + Util::Reference regionDataOffset; + u32 originalLoopStart; + u32 originalLoopEnd; + u32 crc32Value; + }; + static_assert(sizeof(StreamSoundInfo) == 0x50); + + struct TrackInfo { + u8 volume; + u8 pan; + u8 span; + u8 flags; + + Util::Reference toGlobalChannelIndexTable; + }; + + struct TrackInfoTable { + + TrackInfo* GetTrackInfo(u32 index) const; + + Util::ReferenceTable table; + }; + + struct DspAdpcmChannelInfo { + DspAdpcmParam param; + DspAdpcmLoopParam loopParam; + }; + static_assert(sizeof(DspAdpcmChannelInfo) == 0x2c); + + struct ChannelInfo { + + DspAdpcmChannelInfo* GetDspAdpcmChannelInfo() const; + + Util::Reference toDetailChannelInfo; + }; + static_assert(sizeof(ChannelInfo) == 0x8); + + struct ChannelInfoTable { + + ChannelInfo* GetChannelInfo(u32 index) const; + + Util::ReferenceTable table; + }; + + struct InfoBlockBody { + + StreamSoundInfo* GetStreamSoundInfo() const; + TrackInfoTable* GetTrackInfoTable() const; + ChannelInfoTable* GetChannelInfoTable() const; + + Util::Reference toStreamSoundInfo; + Util::Reference toTrackInfoTable; + Util::Reference toChannelInfoTable; + }; + static_assert(sizeof(InfoBlockBody) == 0x18); + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + static_assert(sizeof(InfoBlock) == 0x20); + + struct RegionInfo { + u32 start; + u32 end; + DspAdpcmLoopParam adpcmContext[16]; + bool isEnabled; + u8 padding[87]; + char regionName[64]; + }; + static_assert(sizeof(RegionInfo) == 0x100); + + struct RegionBlock { + BinaryBlockHeader header; + RegionInfo info; + }; + static_assert(sizeof(RegionBlock) == 0x108); + + struct GlobalChannelIndexTable { + Util::Table table; + }; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundFileLoader.h b/include/nn/atk/detail/strm/atk_StreamSoundFileLoader.h new file mode 100644 index 0000000..e925912 --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundFileLoader.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class StreamSoundFileLoader : IRegionInfoReadable { +public: + StreamSoundFileLoader(); + ~StreamSoundFileLoader() override; + + bool LoadFileHeader(StreamSoundFileReader* reader, void* buffer, u64 size); + + bool ReadSeekBlockData(u16* yn1, u16 yn2, s32 blockIndex, s32 channelCount); + bool ReadRegionInfo(StreamSoundFile::RegionInfo* pInfo, u32 regionIndex) const override; + +private: + fnd::FileStream* m_pStream; + u32 m_SeekBlockOffset; + u32 m_RegionDataOffset; + u16 m_RegionInfoBytes; +}; +static_assert(sizeof(StreamSoundFileLoader) == 0x20); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundFileReader.h b/include/nn/atk/detail/strm/atk_StreamSoundFileReader.h new file mode 100644 index 0000000..c38c8bc --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundFileReader.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class StreamSoundFileReader { +public: + StreamSoundFileReader(); + + void Initialize(const void* streamSoundFile); + + static bool IsValidFileHeader(const void* streamSoundFile); + + void Finalize(); + + bool IsTrackInfoAvailable() const; + bool IsOriginalLoopAvailable() const; + + static bool IsOriginalLoopAvailableImpl(const StreamSoundFile::FileHeader* header); + + bool IsCrc32CheckAvailable() const; + bool IsRegionIndexCheckAvailable() const; + + bool ReadStreamSoundInfo(StreamSoundFile::StreamSoundInfo* strmInfo) const; + bool ReadStreamTrackInfo(StreamSoundFile::TrackInfo* pTrackInfo, s32 trackIndex) const; + bool ReadDspAdpcmChannelInfo(DspAdpcmParam* pParam, DspAdpcmLoopParam* pLoopParam, + s32 channelIndex) const; + +private: + StreamSoundFile::FileHeader* m_pHeader; + StreamSoundFile::InfoBlockBody* m_pInfoBlockBody; +}; +static_assert(sizeof(StreamSoundFileReader) == 0x10); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundLoader.h b/include/nn/atk/detail/strm/atk_StreamSoundLoader.h new file mode 100644 index 0000000..8338e96 --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundLoader.h @@ -0,0 +1,306 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nn::atk::detail { +struct IStreamDataDecoderManager; +struct DriverCommandStreamSoundLoadHeader; +struct DriverCommandStreamSoundLoadData; + +struct TrackDataInfo { + u8 volume; + u8 pan; + u8 span; + u8 flags; + u8 mainSend; + u8 fxSend[3]; + u8 lpfFreq; + u8 biquadType; + u8 biquadValue; + u8 channelCount; + u8 channelIndex[2]; +}; +static_assert(sizeof(TrackDataInfo) == 0xe); + +struct TrackDataInfos { + TrackDataInfo track[8]; +}; +static_assert(sizeof(TrackDataInfos) == 0x70); + +struct StreamDataInfoDetail { + void SetStreamSoundInfo(const StreamSoundFile::StreamSoundInfo&, bool); + + SampleFormat sampleFormat; + s32 sampleRate; + bool loopFlag; + position_t loopStart; + size_t sampleCount; + position_t originalLoopStart; + position_t originalLoopEnd; + bool isRevisionCheckEnabled; + bool isRegionIndexCheckEnabled; + u32 revisionValue; + size_t blockSampleCount; + size_t blockSize; + size_t lastBlockSize; + size_t lastBlockSampleCount; + s32 channelCount; + s32 trackCount; + TrackDataInfo trackInfo[8]; + s32 regionCount; +}; +static_assert(sizeof(StreamDataInfoDetail) == 0xd8); + +struct LoadDataParam { + u32 blockIndex; + size_t samples; + position_t sampleBegin; + position_t sampleOffset; + size_t sampleBytes; + bool adpcmContextEnable; + AdpcmContextNotAligned adpcmContext[16]; + s32 loopCount; + bool lastBlockFlag; + bool isStartOffsetOfLastBlockApplied; +}; +static_assert(sizeof(LoadDataParam) == 0x98); + +struct FileStreamHookParam { + SoundArchiveFilesHook* pSoundArchiveFilesHook; + char* itemLabel; +}; +static_assert(sizeof(FileStreamHookParam) == 0x10); + +namespace driver { +class StreamSoundPlayer; + +class StreamSoundLoader; +using StreamSoundLoaderManager = LoaderManager; + +class StreamSoundLoader { +public: + constexpr static size_t DataBlockSizeBase = 0x2000; + constexpr static size_t DataBlockSizeMargin = 0x900; + constexpr static size_t DataBlockSizeMax = DataBlockSizeBase + DataBlockSizeMargin; + + constexpr static u32 FileStreamBufferSize = 0x200; + constexpr static u32 LoadBufferChannelCount = 2; + constexpr static size_t LoadBufferSize = 0x5200; + + class StreamHeaderLoadTask : Task { + public: + StreamHeaderLoadTask(); + ~StreamHeaderLoadTask() override; + + void Execute(TaskProfileLogger& logger) override; + + private: + StreamSoundLoader* m_pLoader; + }; + static_assert(sizeof(StreamHeaderLoadTask) == 0x50); + + class StreamCloseTask : Task { + public: + StreamCloseTask(); + ~StreamCloseTask() override; + + void Execute(TaskProfileLogger& logger) override; + + private: + StreamSoundLoader* m_pLoader; + }; + static_assert(sizeof(StreamCloseTask) == 0x50); + + class StreamDataLoadTask : Task { + public: + StreamDataLoadTask(); + ~StreamDataLoadTask() override; + + void Execute(TaskProfileLogger& logger) override; + + private: + friend StreamSoundLoader; + + void* m_BufferAddress[16]; + u32 m_BufferBlockIndex; + position_t m_StartOffsetSamples; + position_t m_PrefetchOffsetSamples; + StreamSoundLoader* m_pLoader; + util::IntrusiveListNode m_Link; + }; + static_assert(sizeof(StreamDataLoadTask) == 0xf8); + + using StreamDataLoadTaskList = util::IntrusiveList>; + + struct AdpcmInfo { + AdpcmParam param; + AdpcmContext beginContext; + AdpcmContext loopContext; + }; + static_assert(sizeof(AdpcmInfo) == 0xc0); + + struct BlockInfo { + size_t size; + size_t samples; + size_t startOffsetSamples; + size_t startOffsetSamplesAlign; + size_t startOffsetByte; + size_t copyByte; + + }; + static_assert(sizeof(BlockInfo) == 0x30); + + StreamSoundLoader(); + ~StreamSoundLoader(); + + void WaitFinalize(); + + void Initialize(); + void Finalize(); + + void CancelRequest(); + void RequestClose(); + + void RegisterStreamDataDecoderManager(IStreamDataDecoderManager* manager); + void UnregisterStreamDataDecoderManager(IStreamDataDecoderManager* manager); + + void* detail_SetFsAccessLog(fnd::FsAccessLog* pFsAccessLog); + + position_t detail_GetCurrentPosition(); + position_t detail_GetCachePosition(); + + size_t detail_GetCachedLength(); + + void RequestLoadHeader(); + void RequestLoadData(void** bufferAddress, u32 bufferBlockIndex, position_t startOffsetSamples, + position_t prefetchOffsetSamples, s32 priority); + + void Update(); + void ForceFinish(); + + bool IsBusy() const; + bool IsInUse(); + + fnd::FndResult Open(); + void Close(); + + void LoadHeader(); + bool LoadHeader1(DriverCommandStreamSoundLoadHeader* command); + bool LoadHeaderForOpus(DriverCommandStreamSoundLoadHeader* command, + StreamFileType type, DecodeMode decodeMode); + + bool ReadTrackInfoFromStreamSoundFile(StreamSoundFileReader& reader); + + bool SetAdpcmInfo(StreamSoundFileReader& reader, s32 channelCount, AdpcmParam** adpcmParam); + + void UpdateLoadingDataBlockIndex(); + + IStreamDataDecoderManager* SelectStreamDataDecoderManager(StreamFileType, DecodeMode); + + void SetStreamSoundInfoForOpus(const IStreamDataDecoder::DataInfo& dataInfo); + + void LoadData(void** bufferAddress, u32 bufferBlockIndex, size_t startOffsetSamples, + size_t prefetchOffsetSamples, TaskProfileLogger& logger); + bool LoadData1(DriverCommandStreamSoundLoadData* command, void** bufferAddress, + u32 bufferBlockIndex, size_t startOffsetSamples, + size_t prefetchOffsetSamples, TaskProfileLogger& logger); + bool LoadDataForOpus(DriverCommandStreamSoundLoadData* command, void** bufferAddress, + u32 bufferBlockIndex, size_t startOffsetSamples, + size_t prefetchOffsetSamples, TaskProfileLogger& logger); + + bool ApplyStartOffset(s64, s32*); + + void CalculateBlockInfo(BlockInfo&); + + bool LoadAdpcmContextForStartOffset(); + + bool LoadOneBlockDataViaCache(void** bufferAddress, const BlockInfo& blockInfo, + position_t destAddressOffset, bool firstBlock, + bool updateAdpcmContext); + bool LoadOneBlockData(void** bufferAddress, const BlockInfo& blockInfo, + position_t destAddressOffset, bool firstBlock, + bool updateAdpcmContext); + + bool MoveNextRegion(s32*); + + bool DecodeStreamData(void**, IStreamDataDecoder::DecodeType); + + void UpdateLoadingDataBlockIndexForOpus(void**); + + bool IsLoopStartFilePos(u32); + + s32 GetLoadChannelCount(s32); + + bool LoadStreamBuffer(u8*, const BlockInfo&, u32); + bool LoadStreamBuffer(u8*, u64); + + bool SkipStreamBuffer(u64); + + void UpdateAdpcmInfoForStartOffset(const void*, s32, const BlockInfo&); + +private: + friend StreamSoundLoaderManager; + + StreamSoundFileLoader m_FileLoader; + StreamSoundPlayer* m_PlayerHandle; + fnd::FileStream* m_pFileStream; + StreamDataInfoDetail* m_DataInfo; + StreamFileType m_FileType; + DecodeMode m_DecodeMode; + FileStreamHookParam m_FileStreamHookParam; + s32 m_ChannelCount; + u16 m_AssignNumber; + bool m_LoopFlag; + bool m_IsStreamOpenFailureHalt; + position_t m_LoopStart; + position_t m_LoopEnd; + char m_FilePath[SoundArchive::FilePathMax]; + void* m_pExternalData; + size_t m_ExternalDataSize; + void* m_pCacheBuffer; + size_t m_CacheSize; + u32 m_LoadingDataBlockIndex; + u32 m_LastBlockIndex; + u32 m_LoopStartBlockIndex; + position_t m_DataStartFilePos; + position_t m_LoopStartFilePos; + position_t m_LoopStartBlockSampleOffset; + bool m_LoopJumpFlag; + bool m_LoadFinishFlag; + RegionManager m_RegionManager; + StreamHeaderLoadTask m_StreamHeaderLoadTask; + StreamCloseTask m_StreamCloseTask; + StreamDataLoadTaskList m_StreamDataLoadTaskList; + InstancePool m_StreamDataLoadTaskPool; + u8 m_StreamDataLoadTaskArea[0x1f00]; + SampleFormat m_SampleFormat; + AdpcmInfo m_AdpcmInfo[16]; + u32 m_FileStreamBuffer[128]; + IStreamDataDecoder* m_pStreamDataDecoder; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + static IStreamDataDecoderManager* g_pStreamDataDecoderManager; +#else + IStreamDataDecoderManager* m_pStreamDataDecoderManager; +#endif + util::IntrusiveListNode m_LinkForLoaderManager; + + static u8 g_LoadBuffer[LoadBufferSize]; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(StreamSoundLoader) == 0x35c0); +#else +static_assert(sizeof(StreamSoundLoader) == 0x3640); +#endif +} // namespace nn::atk::detail::driver +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundPlayer.h b/include/nn/atk/detail/strm/atk_StreamSoundPlayer.h new file mode 100644 index 0000000..cd62d49 --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundPlayer.h @@ -0,0 +1,344 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nn::atk::detail { +struct StreamSoundDataInfo { + bool loopFlag; + s32 sampleRate; + s64 loopStart; + s64 loopEnd; + s64 compatibleLoopStart; + s64 compatibleLoopEnd; + s32 channelCount; +}; +static_assert(sizeof(StreamSoundDataInfo) == 0x30); + +struct StreamSoundRegionDataInfo { + u32 startSamplePosition; + u32 endSamplePosition; + s32 regionNo; + char regionName[64]; +}; +static_assert(sizeof(StreamSoundRegionDataInfo) == 0x4c); + +namespace driver { +class StreamSoundPlayer : BasicSoundPlayer, SoundThread::PlayerCallback { +public: + enum StartOffsetType { + StartOffsetType_Sample, + StartOffsetType_Millisec, + }; + + struct SetupArg; + struct ItemData { + f32 pitch; + f32 mainSend; + f32 fxSend[3]; + + void Set(const SetupArg& arg); + }; + static_assert(sizeof(ItemData) == 0x14); + + struct TrackData { + f32 volume; + f32 lpfFreq; + s32 biquadType; + f32 biquadValue; + f32 pan; + f32 span; + f32 mainSend; + f32 fxSend[3]; + + void Set(const StreamTrack* pStreamTrack); + }; + static_assert(sizeof(TrackData) == 0x28); + + struct WaveBufferInfo { + position_t sampleBegin; + size_t sampleLength; + s32 loopCount; + }; + static_assert(sizeof(WaveBufferInfo) == 0x18); + + struct PrepareBaseArg { + StartOffsetType startOffsetType; + position_t offset; + s32 delayTime; + s32 delayCount; + UpdateType updateType; +#if NN_SDK_VER < NN_MAKE_VER(4, 4 ,1) + u32 subMixIndex; +#endif + StreamRegionCallback regionCallback; + void* regionCallbackArg; + char filePath[639]; + void* pExternalData; + size_t externalDataSize; + FileStreamHookParam fileStreamHookParam; + }; + static_assert(sizeof(PrepareBaseArg) == 0x2d0); + + struct PrepareArg { + PrepareBaseArg baseArg; + void* cacheBuffer; + size_t cacheSize; + }; + static_assert(sizeof(PrepareArg) == 0x2e0); + + struct PreparePrefetchArg { + PrepareBaseArg baseArg; + void* strmPrefetchFile; + }; + static_assert(sizeof(PreparePrefetchArg) == 0x2d8); + + struct SetupArg { + StreamBufferPool* pBufferPool; + u32 allocChannelCount; + u16 allocTrackFlag; + u8 fileType; + bool loopFlag; + TrackDataInfos trackInfos; + position_t loopStart; + position_t loopEnd; + f32 pitch; + u8 mainSend; + u8 fxSend[3]; +#if NN_SDK_VER >= NN_MAKE_VER(4, 4 ,1) + DecodeMode decodeMode; +#endif + }; +#if NN_SDK_VER < NN_MAKE_VER(4, 4 ,1) + static_assert(sizeof(SetupArg) == 0x98); +#else + static_assert(sizeof(SetupArg) == 0xa0); +#endif + + struct PrefetchIndexInfo { + + void Initialize(const StreamDataInfoDetail& streamDataInfo); + + u32 lastBlockIndex; + position_t loopStartInBlock; + u32 loopStartBlockIndex; + s32 loopBlockCount; + }; + static_assert(sizeof(PrefetchIndexInfo) == 0x18); + + struct PrefetchLoadDataParam : LoadDataParam { + u32 prefetchBlockIndex; + size_t prefetchBlockBytes; + }; + static_assert(sizeof(PrefetchLoadDataParam) == 0xa8); + + StreamSoundPlayer(); + ~StreamSoundPlayer() override; + + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + + bool TryAllocLoader(); + + void Finalize() override; + + void FinishPlayer(); + + void FreeStreamBuffers(); + void FreeVoices(); + void FreeLoader(); + + void Setup(const SetupArg& arg); + void SetupTrack(const SetupArg& arg); + + void Prepare(const PrepareArg& arg); + + void SetPrepareBaseArg(const PrepareBaseArg& arg); + + void RequestLoadHeader(const PrepareArg& arg); + + void PreparePrefetch(const PreparePrefetchArg& arg); + + bool ReadPrefetchFile(StreamSoundPrefetchFileReader& reader); + + bool ApplyStreamDataInfo(const StreamDataInfoDetail& streamDataInfo); + + bool SetupPlayer(); + + bool AllocVoices(); + + bool LoadPrefetchBlocks(StreamSoundPrefetchFileReader& reader); + + void Start() override; + void StartPlayer(); + + void Stop() override; + + void Pause(bool flag) override; + + void UpdatePauseStatus(); + + bool IsLoadingDelayState() const; + bool IsBufferEmpty() const; + + bool ReadStreamDataInfo(StreamDataInfo* strmDataInfo) const; + + position_t GetPlaySamplePosition(bool) const; + f32 GetFilledBufferPercentage() const; + s32 GetBufferBlockCount(WaveBuffer::Status waveBufferStatus) const; + s32 GetTotalBufferBlockCount() const; + + bool LoadHeader(bool result, AdpcmParam** adpcmParam, u16 assignNumber); + + bool CheckPrefetchRevision(const StreamDataInfoDetail& streamDataInfo) const; + + bool AllocStreamBuffers(); + + void UpdateLoadingBlockIndex(); + + bool LoadStreamData(bool result, const LoadDataParam& loadDataParam, u16 assignNumber); + bool LoadStreamData(bool result, const LoadDataParam& loadDataParam, u16 assignNumber, + bool usePrefetchFlag, u32 currentPrefetchBlockIndex, + size_t currentPrefetchBlockBytes); + + bool IsStoppedByLoadingDelay() const; + + static void VoiceCallbackFunc(MultiVoice* voice, + MultiVoice::VoiceCallbackStatus status, void* arg); + + void Update(); + void UpdateBuffer(); + void UpdateVoiceParams(StreamTrack* track); + + bool CheckDiskDriveError(); + + void SetOutputParam(const OutputParam*, const OutputParam&, const TrackData&); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void ApplyTvOutputParamForMultiChannel(OutputParam* outputParam, + MultiVoice* MultiVoice, s32 channelIndex, + MixMode mixMode); +#else + void ApplyTvOutputParamForMultiChannel(OutputParam* outputParam, + OutputAdditionalParam* pOutputAdditionalParam, + MultiVoice* MultiVoice, s32 channelIndex, + MixMode mixMode); +#endif + + void MixSettingForOutputParam(OutputParam* outputParam, s32 channelIndex, MixMode mixMode); + + position_t GetOriginalPlaySamplePosition(position_t, const StreamDataInfoDetail& streamDataInfo) const; + + bool IsValidStartOffset(const StreamDataInfoDetail& streamDataInfo); + + void ApplyTrackDataInfo(const StreamDataInfoDetail& streamDataInfo); + + u64 GetStartOffsetSamples(const StreamDataInfoDetail& streamDataInfo); + + void PreparePrefetchOnLastBlock(PrefetchLoadDataParam*, const PrefetchIndexInfo&); + void PreparePrefetchOnLoopStartBlock(PrefetchLoadDataParam*, const PrefetchIndexInfo&, + StreamSoundPrefetchFileReader& reader); + void PreparePrefetchOnLoopBlock(PrefetchLoadDataParam*, const PrefetchIndexInfo&, u32); + bool PreparePrefetchOnNormalBlock(PrefetchLoadDataParam*, u32, + StreamSoundPrefetchFileReader* reader); + + bool SetAdpcmLoopInfo(StreamSoundPrefetchFileReader& reader, + const StreamDataInfoDetail& streamDataInfo, AdpcmParam* adpcmParam, + AdpcmContextNotAligned* adpcmContext); + bool SetAdpcmInfo(StreamSoundPrefetchFileReader& reader, + const StreamDataInfoDetail& streamDataInfo, AdpcmParam* adpcmParam, + AdpcmContextNotAligned* adpcmContext); + + void SetTrackVolume(u32 trackBitFlag, f32 volume); + void SetTrackInitialVolume(u32 trackBitFlag, u32 volume); + + void SetTrackOutputLine(u32 trackBitFlag, u32 outputLine); + void ResetTrackOutputLine(u32 trackBitFlag); + + void SetTrackTvVolume(u32 trackBitFlag, f32 volume); + void SetTrackChannelTvMixParameter(u32 trackBitFlag, u32 srcChNo, const MixParameter& param); + void SetTrackTvPan(u32 trackBitFlag, f32 pan); + void SetTrackTvSurroundPan(u32 trackBitFlag, f32 span); + void SetTrackTvMainSend(u32 trackBitFlag, f32 send); + void SetTrackTvFxSend(u32 trackBitFlag, AuxBus bus, f32 send); + + StreamTrack* GetPlayerTrack(s32 index); + StreamTrack* GetPlayerTrack(s32 index) const; + + void OnUpdateFrameSoundThread() override; + void OnUpdateFrameSoundThreadWithAudioFrameFrequency() override; + void OnShutdownSoundThread() override; + +private: + bool m_IsInitialized; + bool m_IsPrepared; + bool m_IsFinalizing; + bool m_IsPreparedPrefetch; + bool m_PauseStatus; + bool m_LoadWaitFlag; + bool m_LoadFinishFlag; + bool m_ReportLoadingDelayFlag; + bool m_IsStoppedByLoadingDelay; + bool m_IsRegisterPlayerCallback; + bool m_UseDelayCount; +#if NN_SDK_VER >= NN_MAKE_VER(5, 3, 0) + u8 m_Padding1[2]; +#endif + s32 m_LoopCounter; + s32 m_PlayingBlockLoopCounter; + s32 m_PrepareCounter; + StreamSoundLoaderManager* m_pLoaderManager; + StreamSoundLoader* m_pLoader; + detail::driver::StreamBufferPool* m_pBufferPool; + s32 m_BufferBlockCount; + u32 m_LoadingBufferBlockIndex; + u32 m_PlayingBufferBlockIndex; + u32 m_LastPlayFinishBufferBlockIndex; + StartOffsetType m_StartOffsetType; + position_t m_StartOffset; + s32 m_DelayCount; + u16 m_AssignNumber; + u8 m_FileType; +#if NN_SDK_VER >= NN_MAKE_VER(4, 4 ,1) + DecodeMode m_DecodeMode; +#endif + bool m_LoopFlag; + u8 m_Padding2[2]; + StreamDataInfoDetail m_StreamDataInfo; + position_t m_LoopStart; + position_t m_LoopEnd; + ItemData m_ItemData; + void* m_pStreamPrefetchFile; + AdpcmParam m_PrefetchAdpcmParam[16]; + StreamSoundPrefetchFileReader::PrefetchDataInfo m_PrefetchDataInfo; + position_t m_PrefetchOffset; + bool m_IsPrefetchRevisionCheckEnabled; + u32 m_PrefetchRevisionValue; + s32 m_ChannelCount; + s32 m_TrackCount; + StreamChannel m_Channels[16]; + StreamTrack m_Tracks[8]; + UpdateType m_UpdateType; +#if NN_SDK_VER < NN_MAKE_VER(4, 4 ,1) + u32 m_SubMixIndex; +#endif + WaveBufferInfo m_WaveBufferInfo[32]; + PrepareArg m_PrepareArg; + bool m_IsSucceedPrepare; + SetupArg m_SetupArg; + position_t m_PlaySamplePosition; + position_t m_OriginalPlaySamplePosition; + + static u16 g_TaskRequestIndexCount; + static u16 g_AssignNumberCount; +}; +static_assert(sizeof(StreamSoundPlayer) == 0x11740); +} // namespace nn::atk::detail::driver +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFile.h b/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFile.h new file mode 100644 index 0000000..06f493d --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFile.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class StreamSoundPrefetchFile { +public: + struct PrefetchDataBlock; + struct FileHeader : Util::SoundFileHeader { + + StreamSoundFile::InfoBlock* GetInfoBlock() const; + StreamSoundFile::RegionBlock* GetRegionBlock() const; + PrefetchDataBlock* GetPrefetchDataBlock() const; + + u32 GetPrefetchDataBlockSize() const; + + bool HasRegionBlock() const; + u32 GetRegionBlockSize() const; + u32 GetRegionBlockOffset() const; + + }; + + struct PrefetchSample { + + void* GetSampleAddress(); + + u8 data[1]; + }; + + struct PrefetchData { + + PrefetchSample* GetPrefetchSample(); + + u32 startFrame; + u32 prefetchSize; + u32 reserved[1]; + Util::Reference toPrefetchSample; + }; + static_assert(sizeof(PrefetchData) == 0x14); + + struct PrefetchDataBlockBody { + Util::Table prefetchDataTable; + }; + + struct PrefetchDataBlock { + BinaryBlockHeader header; + PrefetchDataBlockBody body; + }; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFileReader.h b/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFileReader.h new file mode 100644 index 0000000..4b59d80 --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundPrefetchFileReader.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class StreamSoundPrefetchFileReader : IRegionInfoReadable { +public: + struct PrefetchDataInfo { + u32 startFrame; + u32 prefetchSize; + void* dataAddress; + }; + + StreamSoundPrefetchFileReader(); + ~StreamSoundPrefetchFileReader() override; + + void Initialize(const void* streamSoundPrefetchFile); + void Finalize(); + + bool IsValidFileHeader(const void* streamSoundPrefetchFile) const; + + s32 GetRegionDataOffset() const; + u16 GetRegionInfoBytes() const; + + bool IsIncludeRegionInfo() const; + bool IsCrc32CheckAvailable() const; + bool IsRegionIndexCheckAvailable() const; + + bool ReadStreamSoundInfo(StreamSoundFile::StreamSoundInfo* strmInfo) const; + bool ReadDspAdpcmChannelInfo(DspAdpcmParam* pParam, DspAdpcmLoopParam* pLoopParam, + s32 channelIndex) const; + bool ReadPrefetchDataInfo(PrefetchDataInfo* pDataInfo, s32 prefetchIndex) const; + bool ReadRegionInfo(StreamSoundFile::RegionInfo* pInfo, + u32 regionIndex) const override; + +private: + StreamSoundPrefetchFile::FileHeader* m_pHeader; + StreamSoundFile::InfoBlockBody* m_pInfoBlockBody; + StreamSoundPrefetchFile::PrefetchDataBlockBody* m_pPrefetchDataBlockBody; + u32 m_RegionDataOffset; + u16 m_RegionInfoBytes; +}; +static_assert(sizeof(StreamSoundPrefetchFileReader) == 0x28); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/strm/atk_StreamSoundRuntime.h b/include/nn/atk/detail/strm/atk_StreamSoundRuntime.h new file mode 100644 index 0000000..9ec98c0 --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamSoundRuntime.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class StreamSoundRuntime { +public: + constexpr static u32 DefaultStreamBlockCount = 5; + + StreamSoundRuntime(); + ~StreamSoundRuntime(); + + bool Initialize(s32 soundCount, void** pOutAllocatedAddr, const void* endAddr, + void* streamInstanceBuffer, size_t streamInstanceBufferSize); + + static size_t GetRequiredStreamInstanceSize(s32 soundCount); + + bool SetupStreamBuffer(const SoundArchive* pSoundArchive, void* strmBuffer, + size_t strmBufferSize); + bool SetupStreamBuffer(const SoundArchive* pSoundArchive, void* strmBuffer, + size_t strmBufferSize, driver::StreamBufferPool* strmBufferPool); + + size_t GetRequiredStreamBufferSize(const SoundArchive* soundArchive) const; + static u32 GetRequiredStreamBufferTimes(const SoundArchive* soundArchive); + + bool SetupStreamCacheBuffer(const SoundArchive* pSoundArchive, void* streamCacheBuffer, + size_t streamCacheSize); + + void Finalize(); + + static size_t GetRequiredMemorySize(const SoundArchive::SoundArchivePlayerInfo& soundArchivePlayerInfo, + s32 alignment); + + static size_t GetRequiredStreamCacheSize(const SoundArchive* pSoundArchive, + size_t); + + s32 GetActiveCount() const; + s32 GetActiveChannelCount() const; + s32 GetActiveTrackCount() const; + s32 GetFreeCount() const; + + void SetupUserParam(void** pOutAllocatedAddr, size_t adjustSize); + + void Update(); +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + StreamSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo); +#else + StreamSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo, OutputReceiver* pOutputReceiver); +#endif + SoundStartable::StartResult PrepareImpl(const SoundArchive* pSoundArchive, + const SoundDataManager* pSoundDataManager, + SoundArchive::ItemId soundId, + StreamSound* sound, + const SoundArchive::SoundInfo* commonInfo, + const StartInfoReader& startInfoReader); + + void DumpMemory(const SoundArchive* pSoundArchive) const; + +private: + StreamSoundInstanceManager m_StreamSoundInstanceManager; + driver::StreamSoundLoaderManager m_StreamSoundLoaderManager; + driver::StreamBufferPool m_StreamBufferPool; + SoundArchiveFilesHook* m_pSoundArchiveFilesHook; + s32 m_StreamBlockCount; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(StreamSoundRuntime) == 0xb0); +#else +static_assert(sizeof(StreamSoundRuntime) == 0xb8); +#endif +} // namespace nn::atk::detail diff --git a/include/nn/atk/detail/strm/atk_StreamTrack.h b/include/nn/atk/detail/strm/atk_StreamTrack.h new file mode 100644 index 0000000..b0c5c4d --- /dev/null +++ b/include/nn/atk/detail/strm/atk_StreamTrack.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class StreamChannel { +public: + void AppendWaveBuffer(WaveBuffer* pBuffer, bool lastFlag); + +private: + void* m_pBufferAddress; + MultiVoice* m_pVoice; + WaveBuffer m_WaveBuffer[32]; + AdpcmContext m_AdpcmContext[32]; + UpdateType m_UpdateType; +}; +static_assert(sizeof(StreamChannel) == 0x1080); + +class StreamTrack { +public: + StreamTrack(); + ~StreamTrack(); + +private: + bool m_ActiveFlag; + StreamChannel* m_pChannels[2]; + u8 channelCount; + u8 volume; + u8 pan; + u8 span; + u8 mainSend; + u8 fxSend[3]; + u8 lpfFreq; + s8 biquadType; + u8 biquadValue; + u8 flags; + f32 m_Volume; + s32 m_OutputLine; + OutputParam m_TvParam; +}; +static_assert(sizeof(StreamTrack) == 0x80); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_Command.h b/include/nn/atk/detail/thread/atk_Command.h new file mode 100644 index 0000000..0513419 --- /dev/null +++ b/include/nn/atk/detail/thread/atk_Command.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct Command { + Command* next; + u32 id; + u32 tag; + std::uintptr_t memory_next; +}; +static_assert(sizeof(Command) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_CommandManager.h b/include/nn/atk/detail/thread/atk_CommandManager.h new file mode 100644 index 0000000..c2c5a1b --- /dev/null +++ b/include/nn/atk/detail/thread/atk_CommandManager.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +#include + +namespace nn::atk::detail { +class CommandBuffer { +public: + CommandBuffer(); + ~CommandBuffer(); + + void Finalize(); + + void Initialize(void* buffer, size_t bufferSize); + + void* AllocMemory(size_t size); + + void FreeMemory(Command* command); + + size_t GetCommandBufferSize() const; + size_t GetAllocatableCommandSize() const; + size_t GetAllocatedCommandBufferSize() const; + +private: + u32* m_CommandMemoryArea; + size_t m_CommandMemoryAreaSize; + std::uintptr_t m_CommandMemoryAreaBegin; + std::uintptr_t m_CommandMemoryAreaEnd; + bool m_CommandMemoryAreaZeroFlag; +}; +static_assert(sizeof(CommandBuffer) == 0x28); + +class CommandManager { +public: + using ProcessCommandListFunc = void(*)(Command*); + using RequestProcessCommandFunc = void(*)(); + + constexpr static s32 SendCommandQueueCount = 32; + constexpr static s32 RecvCommandQueueCount = 33; + constexpr static s32 InvalidCommand = -1; + + CommandManager(); + ~CommandManager(); + + void Finalize(); + void Initialize(void* commandBuffer, size_t commandBufferSize, ProcessCommandListFunc func); + + void* AllocMemory(size_t size, bool forceProcessCommandFlag); + + bool TryAllocMemory(size_t size); + + void RecvCommandReply(); + + u32 FlushCommand(bool forceFlag, bool forceProcessCommandFlag); + + void WaitCommandReply(u32 tag); + + void RecvCommandReplySync(); + + u32 PushCommand(Command* command); + u32 FlushCommand(bool forceFlag); + + void FinalizeCommandList(Command* command); + + bool IsFinishCommand(u32) const; + + size_t GetCommandBufferSize() const; + size_t GetAllocatableCommandSize() const; + size_t GetAllocatedCommandBufferSize() const; + + s32 GetAllocatedCommandCount() const; + + bool ProcessCommand(); + +private: + bool m_Available; + ProcessCommandListFunc m_pProcessCommandListFunc; + RequestProcessCommandFunc m_pRequestProcessCommandFunc; + os::MessageQueueType m_SendCommandQueue; + std::uintptr_t m_SendCommandQueueBuffer[SendCommandQueueCount]; + bool m_IsInitializedSendMessageQueue; + os::MessageQueueType m_RecvCommandQueue; + std::uintptr_t m_RecvCommandQueueBuffer[RecvCommandQueueCount]; + bool m_IsInitializedRecvMessageQueue; + Command* m_CommandListBegin; + Command* m_CommandListEnd; + std::atomic_int m_CommandListCount; + u32 m_CommandTag; + u32 m_FinishCommandTag; + CommandBuffer m_CommandBuffer; + s32 m_AllocatedCommandCount; +}; +static_assert(sizeof(CommandManager) == 0x310); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_DriverCommand.h b/include/nn/atk/detail/thread/atk_DriverCommand.h new file mode 100644 index 0000000..848f686 --- /dev/null +++ b/include/nn/atk/detail/thread/atk_DriverCommand.h @@ -0,0 +1,529 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace nn::atk::detail { +enum DriverCommandId { + DriverCommandId_Dummy, + DriverCommandId_Debug, + DriverCommandId_Reply, + DriverCommandId_PlayerInit, + DriverCommandId_PlayerPanmode, + DriverCommandId_PlayerPancurve, + DriverCommandId_PlayerFinalize, + DriverCommandId_PlayerStart, + DriverCommandId_PlayerStop, + DriverCommandId_PlayerPause, + DriverCommandId_PlayerParam, + DriverCommandId_PlayerAdditionalSend, + DriverCommandId_PlayerBusMixVolumeUsed, + DriverCommandId_PlayerBusMixVolume, + DriverCommandId_PlayerBusMixVolumeEnabled, + DriverCommandId_PlayerBinaryVolume, + DriverCommandId_PlayerVolumeThroughModeUsed, + DriverCommandId_PlayerVolumeThroughMode, + DriverCommandId_PlayerClearResourceFlag, + DriverCommandId_SeqSetup, + DriverCommandId_SeqLoad, + DriverCommandId_SeqPrepare, + DriverCommandId_SeqSkip, + DriverCommandId_SeqTempoRatio, + DriverCommandId_SeqChannelPrio, + DriverCommandId_SeqSetVar, + DriverCommandId_SeqSetGvar, + DriverCommandId_SeqSetTvar, + DriverCommandId_SeqTrackMute, + DriverCommandId_SeqTrackSilence, + DriverCommandId_SeqTrackVolume, + DriverCommandId_SeqTrackPitch, + DriverCommandId_SeqTrackLpf, + DriverCommandId_SeqTrackBiquad, + DriverCommandId_SeqTrackBankIndex, + DriverCommandId_SeqTrackTranspose, + DriverCommandId_SeqTrackVelocityRange, + DriverCommandId_SeqTrackOutputline, + DriverCommandId_SeqTrackOutputlineReset, + DriverCommandId_SeqTrackTvVolume, + DriverCommandId_SeqTrackTvMixParameter, + DriverCommandId_SeqTrackTvPan, + DriverCommandId_SeqTrackTvSpan, + DriverCommandId_SeqTrackTvMainSend, + DriverCommandId_SeqTrackTvFxSend, + DriverCommandId_WsdPrepare, + DriverCommandId_WsdLoad, + DriverCommandId_WsdChannelPrio, + DriverCommandId_WsdChannelParam, + DriverCommandId_AwsdPrepare, + DriverCommandId_StrmSetup, + DriverCommandId_StrmPrepare, + DriverCommandId_StrmPreparePrefetch, + DriverCommandId_StrmLoadHeader, + DriverCommandId_StrmLoadData, + DriverCommandId_StrmForceFinish, + DriverCommandId_StrmTrackVolume, + DriverCommandId_StrmTrackInitialVolume, + DriverCommandId_StrmTrackOutputline, + DriverCommandId_StrmTrackOutputlineReset, + DriverCommandId_StrmTrackTvVolume, + DriverCommandId_StrmTrackTvMixParameter, + DriverCommandId_StrmTrackTvPan, + DriverCommandId_StrmTrackTvSpan, + DriverCommandId_StrmTrackTvMainSend, + DriverCommandId_StrmTrackTvFxSend, + DriverCommandId_InvalidateData, + DriverCommandId_RegistDisposeCallback, + DriverCommandId_UnregistDisposeCallback, + DriverCommandId_AppendEffect, + DriverCommandId_AppendEffectAux, + DriverCommandId_RemoveEffect, + DriverCommandId_RemoveEffectAux, + DriverCommandId_ClearEffect, + DriverCommandId_SubMixApplyDestination, + DriverCommandId_SubMixUpdateMixVolume, + DriverCommandId_AuxBusVolume, + DriverCommandId_AllVoicesSync, + DriverCommandId_VoicePlay, + DriverCommandId_VoiceWaveInfo, + DriverCommandId_VoiceAdpcmParam, + DriverCommandId_VoiceAppendWaveBuffer, + DriverCommandId_VoicePriority, + DriverCommandId_VoiceVolume, + DriverCommandId_VoicePitch, + DriverCommandId_VoicePanMode, + DriverCommandId_VoicePanCurve, + DriverCommandId_VoicePan, + DriverCommandId_VoiceSpan, + DriverCommandId_VoiceLpf, + DriverCommandId_VoiceBiquad, + DriverCommandId_VoiceOutputLine, + DriverCommandId_VoiceMainOutVolume, + DriverCommandId_VoiceMainSend, + DriverCommandId_VoiceFxSend, +}; + +struct DriverCommandReply : Command { + bool* ptr; +}; +static_assert(sizeof(DriverCommandReply) == 0x20); + +struct DriverCommandPlayerInit : Command { + driver::BasicSoundPlayer* player; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pOutputReceiver; +#endif + bool* availableFlagPtr; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(DriverCommandPlayerInit) == 0x28); +#else +static_assert(sizeof(DriverCommandPlayerInit) == 0x30); +#endif + +struct DriverCommandPlayerPanParam : Command { + driver::BasicSoundPlayer* player; + u8 panMode; + u8 panCurve; + u8 padding[2]; +}; +static_assert(sizeof(DriverCommandPlayerPanParam) == 0x28); + +struct DriverCommandPlayer : Command { + driver::BasicSoundPlayer* player; + bool flag; + u8 padding[3]; +}; +static_assert(sizeof(DriverCommandPlayer) == 0x28); + +struct DriverCommandPlayerParam : Command { + driver::BasicSoundPlayer* player; + f32 volume; + f32 pitch; + f32 lpfFreq; + s32 biquadFilterType; + f32 biquadFilterValue; + u32 outputLineFlag; + OutputParam tvParam; +}; +static_assert(sizeof(DriverCommandPlayerParam) == 0x88); + +struct DriverCommandPlayerAdditionalSend : Command { + driver::BasicSoundPlayer* player; + s32 bus; + f32 send; +}; +static_assert(sizeof(DriverCommandPlayerAdditionalSend) == 0x28); + +struct DriverCommandPlayerBusMixVolumeUsed : Command { + driver::BasicSoundPlayer* player; + bool isUsed; +}; +static_assert(sizeof(DriverCommandPlayerBusMixVolumeUsed) == 0x28); + +struct DriverCommandPlayerBusMixVolume : Command { + driver::BasicSoundPlayer* player; + OutputBusMixVolume tvBusMixVolume; +}; +static_assert(sizeof(DriverCommandPlayerBusMixVolume) == 0xe0); + +struct DriverCommandPlayerBusMixVolumeEnabled : Command { + driver::BasicSoundPlayer* player; + s32 bus; + bool isEnabled; +}; +static_assert(sizeof(DriverCommandPlayerBusMixVolumeEnabled) == 0x28); + +struct DriverCommandPlayerBinaryVolume : Command { + driver::BasicSoundPlayer* player; + f32 volume; +}; +static_assert(sizeof(DriverCommandPlayerBinaryVolume) == 0x28); + +struct DriverCommandPlayerVolumeThroughModeUsed : Command { + driver::BasicSoundPlayer* player; + bool isVolumeThroughModeUsed; +}; +static_assert(sizeof(DriverCommandPlayerVolumeThroughModeUsed) == 0x28); + +struct DriverCommandPlayerVolumeThroughMode : Command { + driver::BasicSoundPlayer* player; + s32 bus; + u8 volumeThroughMode; +}; +static_assert(sizeof(DriverCommandPlayerVolumeThroughMode) == 0x28); + +struct DriverCommandPlayerClearResourceFlag : Command { + driver::BasicSoundPlayer* player; +}; +static_assert(sizeof(DriverCommandPlayerClearResourceFlag) == 0x20); + +struct DriverCommandSequenceSoundSetup : Command { + driver::SequenceSoundPlayer* player; + driver::SequenceSoundPlayer::SetupArg arg; + u8 channelPriority; + bool isReleasePriorityFix; + std::uintptr_t userproc; + void* userprocArg; +}; +static_assert(sizeof(DriverCommandSequenceSoundSetup) == 0x50); + +struct DriverCommandSequenceSoundLoad : Command { + driver::SequenceSoundPlayer* player; + driver::SequenceSoundPlayer::StartInfo startInfo; + driver::SequenceSoundLoader::Arg arg; +}; +static_assert(sizeof(DriverCommandSequenceSoundLoad) == 0xa0); + +struct DriverCommandSequenceSoundPrepare : Command { + driver::SequenceSoundPlayer* player; + driver::SequenceSoundPlayer::PrepareArg arg; +}; +static_assert(sizeof(DriverCommandSequenceSoundPrepare) == 0x80); + +struct DriverCommandSequenceSoundSkip : Command { + driver::SequenceSoundPlayer* player; + s32 offsetType; + s32 offset; +}; +static_assert(sizeof(DriverCommandSequenceSoundSkip) == 0x28); + +struct DriverCommandSequenceSoundTempoRatio : Command { + driver::SequenceSoundPlayer* player; + f32 tempoRatio; +}; +static_assert(sizeof(DriverCommandSequenceSoundTempoRatio) == 0x28); + +struct DriverCommandSequenceSoundChannelPrio : Command { + driver::SequenceSoundPlayer* player; + u8 priority; + u8 padding[3]; +}; +static_assert(sizeof(DriverCommandSequenceSoundChannelPrio) == 0x28); + +struct DriverCommandSequenceSoundSetVar : Command { + driver::SequenceSoundPlayer* player; + s32 trackNo; + s32 varNo; + s32 var; +}; +static_assert(sizeof(DriverCommandSequenceSoundSetVar) == 0x30); + +struct DriverCommandSequenceSoundTrack : Command { + driver::SequenceSoundPlayer* player; + u32 trackBitFlag; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrack) == 0x28); + +struct DriverCommandSequenceSoundTrackMute : DriverCommandSequenceSoundTrack { + s32 mute; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackMute) == 0x28); + +struct DriverCommandSequenceSoundTrackSilence : DriverCommandSequenceSoundTrack { + bool silenceFlag; + s32 fadeFrames; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackSilence) == 0x30); + +struct DriverCommandSequenceSoundTrackParam : DriverCommandSequenceSoundTrack { + f32 value; + u32 uint32Value; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackParam) == 0x30); + +struct DriverCommandSequenceSoundTrackBiquad : DriverCommandSequenceSoundTrack { + s32 type; + f32 value; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackBiquad) == 0x30); + +struct DriverCommandSequenceSoundTrackBankIndex : DriverCommandSequenceSoundTrack { + s32 bankIndex; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackBankIndex) == 0x28); + +struct DriverCommandSequenceSoundTrackTranspose : DriverCommandSequenceSoundTrack { + s8 transpose; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackTranspose) == 0x28); + +struct DriverCommandSequenceSoundTrackVelocityRange : DriverCommandSequenceSoundTrack { + u8 range; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackVelocityRange) == 0x28); + +struct DriverCommandSequenceSoundTrackOutputLine : DriverCommandSequenceSoundTrack { + u32 outputLine; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackOutputLine) == 0x28); + +struct DriverCommandSequenceSoundTrackMixParameter : DriverCommandSequenceSoundTrack { + u32 trackBitFlag; + u32 srcChNo; + MixParameter param; + u32 drcIndex; +}; +static_assert(sizeof(DriverCommandSequenceSoundTrackMixParameter) == 0x48); + +struct DriverCommandWaveSoundPrepare : Command { + driver::WaveSoundPlayer* player; + driver::WaveSoundPlayer::StartInfo startInfo; + driver::WaveSoundPlayer::PrepareArg arg; +}; +static_assert(sizeof(DriverCommandWaveSoundPrepare) == 0x60); + +struct DriverCommandWaveSoundLoad : Command { + driver::WaveSoundPlayer* player; + driver::WaveSoundPlayer::StartInfo startInfo; + driver::WaveSoundLoader::Arg arg; +}; +static_assert(sizeof(DriverCommandWaveSoundLoad) == 0x78); + +struct DriverCommandWaveSoundChannelPrio : Command { + driver::WaveSoundPlayer* player; + u8 priority; + u8 padding[3]; +}; +static_assert(sizeof(DriverCommandWaveSoundChannelPrio) == 0x28); + +struct DriverCommandWaveSoundChannelParam : Command { + driver::WaveSoundPlayer* player; + u8 priority; + bool isReleasePriorityFix; + u8 padding[2]; +}; +static_assert(sizeof(DriverCommandWaveSoundChannelParam) == 0x28); + +struct DriverCommandAdvancedWaveSoundPrepare : Command { + driver::AdvancedWaveSoundPlayer* player; + driver::AdvancedWaveSoundPlayer::PrepareParameter parameter; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(DriverCommandAdvancedWaveSoundPrepare) == 0x40); +#else +static_assert(sizeof(DriverCommandAdvancedWaveSoundPrepare) == 0x38); +#endif + +struct DriverCommandStreamSoundSetup : Command { + driver::StreamSoundPlayer* player; + driver::StreamSoundPlayer::SetupArg arg; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(DriverCommandStreamSoundSetup) == 0xb8); +#else +static_assert(sizeof(DriverCommandStreamSoundSetup) == 0xc0); +#endif +struct DriverCommandStreamSoundPrepare : Command { + driver::StreamSoundPlayer* player; + driver::StreamSoundPlayer::PrepareArg arg; +}; +static_assert(sizeof(DriverCommandStreamSoundPrepare) == 0x300); + +struct DriverCommandStreamSoundPreparePrefetch : Command { + driver::StreamSoundPlayer* player; + driver::StreamSoundPlayer::PreparePrefetchArg arg; +}; +static_assert(sizeof(DriverCommandStreamSoundPreparePrefetch) == 0x2f8); + +struct DriverCommandStreamSoundLoadHeader : Command { + driver::StreamSoundPlayer* player; + AdpcmParam* adpcmParam[16]; + bool result; + u16 assignNumber; +}; +static_assert(sizeof(DriverCommandStreamSoundLoadHeader) == 0xa8); + +struct DriverCommandStreamSoundLoadData : Command { + driver::StreamSoundPlayer* player; + LoadDataParam loadDataParam; + bool result; + u16 assignNumber; +}; +static_assert(sizeof(DriverCommandStreamSoundLoadData) == 0xc0); + +struct DriverCommandStreamSoundForceFinish : Command { + driver::StreamSoundPlayer* player; +}; +static_assert(sizeof(DriverCommandStreamSoundForceFinish) == 0x20); + +struct DriverCommandStreamSoundTrackParam : Command { + driver::StreamSoundPlayer* player; + u32 trackBitFlag; + f32 value; + u32 uint32Value; + u32 drcIndex; +}; +static_assert(sizeof(DriverCommandStreamSoundTrackParam) == 0x30); + +struct DriverCommandStreamSoundTrackInitialVolume : Command { + driver::StreamSoundPlayer* player; + u32 trackBitFlag; + u32 value; +}; +static_assert(sizeof(DriverCommandStreamSoundTrackInitialVolume) == 0x28); + +struct DriverCommandStreamSoundTrackMixParameter : Command { + driver::StreamSoundPlayer* player; + u32 trackBitFlag; + u32 srcChNo; + MixParameter param; + u32 drcIndex; +}; +static_assert(sizeof(DriverCommandStreamSoundTrackMixParameter) == 0x48); + +struct DriverCommandInvalidateData : Command { + void* mem; + size_t size; +}; +static_assert(sizeof(DriverCommandInvalidateData) == 0x28); + +struct DriverCommandDisposeCallback : Command { + driver::DisposeCallback* callback; +}; +static_assert(sizeof(DriverCommandDisposeCallback) == 0x20); + +struct DriverCommandEffect : Command { + s32 bus; + EffectBase* effect; + void* effectBuffer; + size_t effectBufferSize; + OutputMixer* pOutputMixer; +}; +static_assert(sizeof(DriverCommandEffect) == 0x40); + +struct DriverCommandEffectAux : Command { + s32 bus; + EffectAux* effect; + void* effectBuffer; + size_t effectBufferSize; + OutputMixer* pOutputMixer; +}; +static_assert(sizeof(DriverCommandEffectAux) == 0x40); + +struct DriverCommandSubMixApplyDestination : Command { +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pReceiver; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(DriverCommandSubMixApplyDestination) == 0x18); +#else +static_assert(sizeof(DriverCommandSubMixApplyDestination) == 0x20); +#endif + +struct DriverCommandSubMixUpdateMixVolume : Command { +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pReceiver; +#endif + s32 srcBus; + s32 srcChannel; + s32 dstBus; + s32 dstChannel; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(DriverCommandSubMixUpdateMixVolume) == 0x28); +#else +static_assert(sizeof(DriverCommandSubMixUpdateMixVolume) == 0x30); +#endif + +struct DriverCommandAuxBusVolume : Command { + AuxBus bus; + s32 subMixIndex; + f32 volume; + s32 fadeFrames; +}; +static_assert(sizeof(DriverCommandAuxBusVolume) == 0x28); + +struct DriverCommandAllVoicesSync : Command { + u32 syncFlag; +}; +static_assert(sizeof(DriverCommandAllVoicesSync) == 0x20); + +struct DriverCommandVoice : Command { + driver::MultiVoice* voice; +}; +static_assert(sizeof(DriverCommandVoice) == 0x20); + +struct DriverCommandVoicePlay : DriverCommandVoice { + enum State { + State_Start, + State_Stop, + State_PauseOn, + State_PauseOff, + }; + + State state; +}; +static_assert(sizeof(DriverCommandVoicePlay) == 0x28); + +struct DriverCommandVoiceWaveInfo : DriverCommandVoice { + SampleFormat format; + s32 sampleRate; + s32 interpolationType; +}; +static_assert(sizeof(DriverCommandVoiceWaveInfo) == 0x30); + +struct DriverCommandVoiceAdpcmParam : DriverCommandVoice { + s32 channel; + s32 voiceOut; + AdpcmParam* param; +}; +static_assert(sizeof(DriverCommandVoiceAdpcmParam) == 0x30); + +class DriverCommand : CommandManager { +public: + static void ProcessCommandList(Command* commandList); + + DriverCommand(); + + void Initialize(void* commandBuffer, size_t commandBufferSize); + + void RequestProcessCommand(); +}; +static_assert(sizeof(DriverCommand) == 0x310); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_SoundThread.h b/include/nn/atk/detail/thread/atk_SoundThread.h new file mode 100644 index 0000000..170a626 --- /dev/null +++ b/include/nn/atk/detail/thread/atk_SoundThread.h @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace nn::atk::detail::driver { +struct SoundThreadLock {}; +struct AtkStateAndParameterUpdateLock {}; + +class SoundThread : fnd::Thread::Handler { +public: + enum Message { + Message_HwCallback = 0x10000000, + Message_Shutdown = 0x20000000, + Message_ForceWakeup = 0x30000000, + }; + + using ProfileFunc = void(*)(os::Tick*); + + constexpr static u32 ThreadMessageBuffferSize = 32; + + constexpr static u32 RendererEventWaitTimeoutMilliSeconds = 100; + + class SoundFrameCallback { + public: + virtual ~SoundFrameCallback(); + + virtual void OnBeginSoundFrame(); + virtual void OnEndSoundFrame(); + + private: + friend SoundThread; + + util::IntrusiveListNode m_Link; + }; + + using SoundFrameCallbackList = util::IntrusiveList>; + + class PlayerCallback { + public: + virtual ~PlayerCallback(); + + virtual void OnUpdateFrameSoundThread() = 0; + virtual void OnUpdateFrameSoundThreadWithAudioFrameFrequency() = 0; + virtual void OnShutdownSoundThread() = 0; + + private: + friend SoundThread; + + util::IntrusiveListNode m_Link; + }; + + using PlayerCallbackList = util::IntrusiveList>; + + ~SoundThread() override; + + bool CreateSoundThread(s32 threadPriority, void* stackBase, size_t stackSize, + s32 idealCoreNumber, u32 affinityMask); + + void Initialize(void* performanceFrameBuffer, size_t performanceFrameBufferSize, + bool isProfilingEnabled); + void Initialize(void* performanceFrameBuffer, size_t performanceFrameBufferSize, + bool isProfilingEnabled, bool isDetailSoundThreadProfilerEnabled, + bool isUserThreadRenderingEnabled); + + void Destroy(); + + void Finalize(); + + void UpdateLowLevelVoices(); + + void ForceWakeup(); + + void RegisterSoundFrameUserCallback(SoundFrameUserCallback callback, std::uintptr_t callbackArg); + void ClearSoundFrameUserCallback(); + + void RegisterThreadBeginUserCallback(SoundThreadUserCallback, std::uintptr_t callbackArg); + void ClearThreadBeginUserCallback(); + + void RegisterThreadEndUserCallback(SoundThreadUserCallback, std::uintptr_t callbackArg); + void ClearThreadEndUserCallback(); + + void RegisterSoundFrameCallback(SoundFrameCallback* callback); + void UnregisterSoundFrameCallback(SoundFrameCallback* callback); + + void RegisterPlayerCallback(PlayerCallback* callback); + void UnregisterPlayerCallback(PlayerCallback* callback); + + void LockAtkStateAndParameterUpdate(); + void UnlockAtkStateAndParameterUpdate(); + + void RegisterAudioRendererPerformanceReader(AudioRendererPerformanceReader& performanceReader); + + void RegisterSoundThreadUpdateProfileReader(SoundThreadUpdateProfileReader& profileReader); + void UnregisterSoundThreadUpdateProfileReader(SoundThreadUpdateProfileReader& profileReader); + + void RegisterSoundThreadInfoRecorder(ThreadInfoRecorder& recorder); + void UnregisterSoundThreadInfoRecorder(ThreadInfoRecorder& recorder); + + void FrameProcess(UpdateType updateType); + + void RecordPerformanceInfo(audio::PerformanceInfo* src, os::Tick beginTick, + os::Tick endTick, u32 nwVoiceCount); + + void EffectFrameProcess(); + + void RecordUpdateProfile(const SoundThreadUpdateProfile& threadUpdateProfile); + + u32 Run(void* param) override; + +private: + fnd::Thread m_Thread; + os::MessageQueue m_BlockingQueue; + std::uintptr_t m_MsgBuffer[ThreadMessageBuffferSize]; + u32 m_AxCallbackCounter; + fnd::CriticalSection m_CriticalSection; + fnd::CriticalSection m_UpdateAtkStateAndParameterSection; + SoundFrameCallbackList m_SoundFrameCallbackList; + PlayerCallbackList m_PlayerCallbackList; + SoundFrameUserCallback m_UserCallback; + std::uintptr_t m_UserCallbackArg; + SoundThreadUserCallback m_ThreadBeginUserCallback; + std::uintptr_t m_ThreadBeginUserCallbackArg; + SoundThreadUserCallback m_ThreadEndUserCallback; + std::uintptr_t m_ThreadEndUserCallbackArg; + s32 m_SoundThreadAffinityMask; + bool m_CreateFlag; + bool m_PauseFlag; + os::Tick m_LastPerformanceFrameBegin; + os::Tick m_LastPerformanceFrameEnd; + void* m_pPerformanceFrameUpdateBuffer[3]; + size_t m_PerformanceFrameUpdateBufferSize; + s32 m_CurrentPerformanceFrameBufferIndex; + bool m_IsProfilingEnabled; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + ProfileFunc m_pSoundThreadProfileFunc; + bool m_IsUserThreadRenderingEnabled; +#endif + ProfileReaderList m_ProfileReaderList; + AudioRendererPerformanceReader* m_pAudioRendererPerformanceReader; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + SoundThreadInfoRecorderList m_InfoRecorderList; + fnd::CriticalSection m_LockRecordInfo; +#endif + SoundThreadUpdateProfile m_LastUpdateProfile; + SoundThreadUpdateProfileReaderList m_UpdateProfileReaderList; + fnd::CriticalSection m_LockUpdateProfile; + std::atomic_int m_RendererEventWaitTimeMilliSeconds; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SoundThread) == 0x4c8); +#else +static_assert(sizeof(SoundThread) == 0x508); +#endif +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_Task.h b/include/nn/atk/detail/thread/atk_Task.h new file mode 100644 index 0000000..a89cf9b --- /dev/null +++ b/include/nn/atk/detail/thread/atk_Task.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class TaskManager; + +class Task { +public: + enum Status { + Status_Free, + Status_Append, + Status_Execute, + Status_Done, + Status_Cancel, + }; + + Task(); + + virtual ~Task(); + virtual void Execute(TaskProfileLogger& logger) = 0; + +private: + friend TaskManager; + + util::IntrusiveListNode m_TaskLink; + os::Event m_Event; + Status m_Status; + u32 m_Id; +}; +static_assert(sizeof(Task) == 0x48); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_TaskManager.h b/include/nn/atk/detail/thread/atk_TaskManager.h new file mode 100644 index 0000000..d962b5f --- /dev/null +++ b/include/nn/atk/detail/thread/atk_TaskManager.h @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail { +class TaskManager { +public: + using TaskList = util::IntrusiveList>; + + enum Message { + Message_Append, + }; + + enum TaskPriority { + TaskPriority_Low, + TaskPriority_Middle, + TaskPriority_High, + }; + + constexpr static u32 PriorityCount = 3; + constexpr static u32 ThreadMessageBufferSize = 32; + + TaskManager(); + ~TaskManager(); + + void Initialize(bool isEnableProfiling); + void Finalize(); + + void AppendTask(Task* task, TaskPriority priority); + + Task* GetNextTask(TaskPriority priority, bool); + + Task* PopTask(); + Task* PeekTask(); + + void ExecuteTask(); + void CancelTask(Task* task); + + bool TryRemoveTask(Task* task); + + void CancelTaskById(u32 id); + void RemoveTaskById(u32 id); + + void CancelAllTask(); + + void WaitTask(); + void CancelWaitTask(); + +private: + TaskList m_TaskList[PriorityCount]; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + Task* m_ActiveTask; +#endif + bool m_IsWaitTaskCancel; + fnd::CriticalSection m_CriticalSection; + os::MessageQueue m_BlockingQueue; + std::uintptr_t m_MsgBuffer[ThreadMessageBufferSize]; + TaskProfileLogger m_TaskProfileLogger; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(TaskManager) == 0x1e0); +#else +static_assert(sizeof(TaskManager) == 0x1d8); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_TaskThread.h b/include/nn/atk/detail/thread/atk_TaskThread.h new file mode 100644 index 0000000..eae3d2b --- /dev/null +++ b/include/nn/atk/detail/thread/atk_TaskThread.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +namespace nn::atk::detail { +class TaskThread : fnd::Thread::Handler { +public: + TaskThread(); + ~TaskThread() override; + + void Destroy(); + + bool Create(s32 priority, void* stackBase, size_t stackSize, + s32 idealCoreNumber, u32 affinityMask, FsPriority fsPriority); + + u32 Run(void* param) override; + +private: + fnd::Thread m_Thread; + fnd::CriticalSection m_CriticalSection; + bool m_IsFinished; + bool m_IsCreated; + FsPriority m_FsPriority; +}; +static_assert(sizeof(TaskThread) == 0x220); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/thread/atk_ThreadInfoReader.h b/include/nn/atk/detail/thread/atk_ThreadInfoReader.h new file mode 100644 index 0000000..29202a5 --- /dev/null +++ b/include/nn/atk/detail/thread/atk_ThreadInfoReader.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +namespace detail { +class ThreadInfoRecorder { +public: + util::IntrusiveListNode m_List; + +private: + void* m_Buffer; + size_t m_BufferSize; + size_t m_WritePosition; + std::atomic_ulong m_ReadPosition; + std::atomic_int m_RecordFrameCount; + std::atomic_bool m_IsAllocationFailed; +}; +static_assert(sizeof(ThreadInfoRecorder) == 0x38); +} // namespace nn::atk::detail + +using SoundThreadInfoRecorder = detail::ThreadInfoRecorder; +using SoundThreadInfoRecorderList = util::IntrusiveList>; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_BinaryFileFormat.h b/include/nn/atk/detail/util/atk_BinaryFileFormat.h new file mode 100644 index 0000000..2fa628e --- /dev/null +++ b/include/nn/atk/detail/util/atk_BinaryFileFormat.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct BinaryFileHeader { + s32 signature; + u16 byteOrder; + u16 headerSize; + u32 version; + u32 fileSize; + u16 dataBlocks; + u16 reserved; +}; +static_assert(sizeof(BinaryFileHeader) == 0x14); + +struct BinaryBlockHeader { + // Named "kind", but functionally the same as BinaryFileHeader.signature + s32 kind; + u32 size; +}; +static_assert(sizeof(BinaryBlockHeader) == 0x8); + +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_BinaryTypes.h b/include/nn/atk/detail/util/atk_BinaryTypes.h new file mode 100644 index 0000000..5ce66ce --- /dev/null +++ b/include/nn/atk/detail/util/atk_BinaryTypes.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +struct BinaryTypes { + NN_NO_COPY(BinaryTypes); + NN_NO_MOVE(BinaryTypes); + + template + struct Table { + CountType count; + T item[1]; + }; + + struct Reference { + u32 offset; + }; + static_assert(sizeof(Reference) == 0x4); + + struct ReferenceTable : Table {}; +}; + +}; \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_CurveAdshr.h b/include/nn/atk/detail/util/atk_CurveAdshr.h new file mode 100644 index 0000000..5f9101d --- /dev/null +++ b/include/nn/atk/detail/util/atk_CurveAdshr.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class CurveAdshr { +public: + enum Status { + Status_Attack, + Status_Hold, + Status_Decay, + Status_Sustain, + Status_Release, + }; + + constexpr static f32 VolumeInit = -90.4; + constexpr static f32 AttackInit = 127; + constexpr static u32 HoldInit = 0; + constexpr static f32 DecayInit = 127; + constexpr static f32 SustainInit = 127; + constexpr static f32 ReleaseInit = 127; + + constexpr static u32 DecibelSquareTableSize = 128; + constexpr static u32 CalcDecibelScaleMax = 127; + + constexpr static u16 DecibelSquareTable[DecibelSquareTableSize] = { + 64813, 64814, 64815, 64885, 64935, 64974, 65006, 65033, + 65056, 65076, 65094, 65111, 65126, 65140, 65153, 65165, + 65176, 65187, 65197, 65206, 65215, 65223, 65231, 65239, + 65247, 65254, 65260, 65267, 65273, 65279, 65285, 65291, + 65297, 65302, 65307, 65312, 65317, 65322, 65326, 65331, + 65335, 65340, 65344, 65348, 65352, 65356, 65360, 65363, + 65367, 65371, 65374, 65378, 65381, 65384, 65387, 65391, + 65394, 65397, 65400, 65403, 65406, 65409, 65411, 65414, + 65417, 65420, 65422, 65425, 65427, 65430, 65433, 65435, + 65437, 65440, 65442, 65445, 65447, 65449, 65451, 65454, + 65456, 65458, 65460, 65462, 65464, 65466, 65468, 65470, + 65472, 65474, 65476, 65478, 65480, 65482, 65484, 65486, + 65487, 65489, 65491, 65493, 65494, 65496, 65498, 65500, + 65501, 65503, 65505, 65506, 65508, 65509, 65511, 65513, + 65514, 65516, 65517, 65519, 65520, 65522, 65523, 65525, + 65526, 65528, 65529, 65530, 65532, 65533, 65535, 0, + }; + + CurveAdshr(); + + void Initialize(f32 initDecibel); + + void SetAttack(s32 attack); + void SetHold(s32 hold); + void SetDecay(s32 decay); + void SetSustain(s32 sustain); + void SetRelease(s32 release); + + void Reset(f32 initDecibel); + + f32 GetValue() const; + + void Update(s32 msec); + + static u16 CalcDecibelSquare(s32); + static f32 CalcRelease(s32); + +private: + Status m_Status{Status_Attack}; + f32 m_Value{-904.0}; + f32 m_Decay{65535.0}; + f32 m_Release{65535.0}; + f32 m_Attack{0.0}; + u16 m_Hold{0}; + u16 m_HoldCounter; + u8 m_Sustain{127}; + u8 m_Padding[3]; +}; +static_assert(sizeof(CurveAdshr) == 0x1c); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_CurveLfo.h b/include/nn/atk/detail/util/atk_CurveLfo.h new file mode 100644 index 0000000..ed90e6e --- /dev/null +++ b/include/nn/atk/detail/util/atk_CurveLfo.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +namespace nn::atk::detail { +f32 CurveSine(f32 arg); +f32 CurveTriangle(f32 arg); +f32 CurveSaw(f32 arg); +f32 CurveSquare(f32 arg); +f32 CurveRandom(f32 arg); + +struct CurveLfoParam { + enum CurveType { + CurveType_Min, + CurveType_UserMin = 0x40, + CurveType_Max = 0x7f, + CurveType_UserMax = CurveType_Max, + + CurveType_Sine = CurveType_Min, + CurveType_Triangle, + CurveType_Saw, + CurveType_Square, + CurveType_Random, + + CurveType_Count = 0x80, + }; + + void Initialize(); + + f32 depth; + f32 speed; + u32 delay; + u8 range; + u8 curve; + u8 phase; + u8 padding[1]; +}; +static_assert(sizeof(CurveLfoParam) == 0x10); + +class CurveLfo { +public: + using CurveFunc = f32(*)(f32); + + static void InitializeCurveTable(); + + void RegisterUserCurve(CurveFunc curveFunc, u32); + void UnregisterUserCurve(u32); + + void Reset(); + void Update(s32 msec); + + f32 GetValue() const; + +private: + CurveLfoParam m_Param; + u32 m_DelayCounter; + f32 m_Counter; + f32 m_RandomValue; + bool m_IsStart; + bool m_IsNext; + u8 m_Padding[2]; +}; +static_assert(sizeof(CurveLfo) == 0x20); + +static CurveLfo::CurveFunc g_CurveFuncTable[5]; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_FrameHeap.h b/include/nn/atk/detail/util/atk_FrameHeap.h new file mode 100644 index 0000000..0333dc9 --- /dev/null +++ b/include/nn/atk/detail/util/atk_FrameHeap.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk::detail { +class FrameHeap { +public: + using DisposeCallback = void(*)(void*, size_t, void*); + using HeapCallback = void(*)(void*); + + constexpr static s32 HeapAlign = 64; + + class Block { + public: + Block(); + + private: + friend FrameHeap; + + util::IntrusiveListNode m_Link; + void* m_pBuffer; + size_t m_Size; + DisposeCallback m_Callback; + void* m_pCallbackArg; + HeapCallback m_HeapCallback; + void* m_pHeapCallbackArg; + }; + + using BlockList = util::IntrusiveList>; + + class Section { + public: + Section(); + ~Section(); + + void* AppendBlock(Block* block); + + void Dump(const SoundDataManager&, const SoundArchive&) const; + + private: + friend FrameHeap; + + util::IntrusiveListNode m_Link; + BlockList m_BlockList; + bool m_UseCallback; + }; + + using SectionList = util::IntrusiveList>; + + FrameHeap(); + ~FrameHeap(); + + void Destroy(); + + bool Create(void* startAddress, size_t size); + + bool NewSection(); + void ClearSection(); + + void Clear(); + + void* Alloc(size_t size, DisposeCallback callback, void* callbackArg, + HeapCallback heapCallback, void* heapCallbackArg); + + s32 SaveState(); + + bool ProcessCallback(s32 level); + + void LoadState(s32 state); + + s32 GetCurrentLevel() const; + size_t GetSize() const; + size_t GetFreeSize() const; + + void Dump(const SoundDataManager&, const SoundArchive&) const; + +private: + fnd::FrameHeapImpl* m_pHeap; + SectionList m_SectionList; +}; +static_assert(sizeof(FrameHeap) == 0x18); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_InstancePool.h b/include/nn/atk/detail/util/atk_InstancePool.h new file mode 100644 index 0000000..2126c0e --- /dev/null +++ b/include/nn/atk/detail/util/atk_InstancePool.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace nn::atk::detail { +class PoolImpl { +public: + s32 CreateImpl(void* buffer, size_t size, size_t objSize); + s32 CreateImpl(void* buffer, size_t size, size_t objSize, + size_t alignment); + + void DestroyImpl(); + + s32 CountImpl() const; + + void* AllocImpl(); + + void FreeImpl(void* ptr); + +private: + PoolImpl* m_pNext; + void* m_pBuffer; + size_t m_BufferSize; +}; +static_assert(sizeof(PoolImpl) == 0x18); + +class BufferPool : PoolImpl {}; + +template +class InstancePool : PoolImpl {}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_MemoryFileStream.h b/include/nn/atk/detail/util/atk_MemoryFileStream.h new file mode 100644 index 0000000..8c1b69a --- /dev/null +++ b/include/nn/atk/detail/util/atk_MemoryFileStream.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class MemoryFileStream : fnd::FileStream { +public: + MemoryFileStream(void* buffer, size_t size); + ~MemoryFileStream() override; + + void Close() override; + + size_t Read(void* buf, size_t length, fnd::FndResult* result) override; + fnd::FndResult Seek(position_t offset, fnd::Stream::SeekOrigin origin) override; + + bool IsOpened() const override; + + size_t Write(const void* buf, size_t length, fnd::FndResult* result) override; + + position_t GetCurrentPosition() const override; + + size_t GetSize() const override; + + bool CanRead() const override; + bool CanWrite() const override; + bool CanSeek() const override; + + fnd::FndResult Open(const char* filePath, AccessMode openMode) override; + void Flush() override; + + void EnableCache(void* buffer, size_t length) override; + void DisableCache() override; + bool IsCacheEnabled() const override; + + s32 GetIoBufferAlignment() const override; + + bool CanSetFsAccessLog() const override; + void* SetFsAccessLog(fnd::FsAccessLog* pFsAccessLog) override; + + position_t GetCachePosition() override; + size_t GetCachedLength() override; + +private: + void* m_pBuffer; + size_t m_Size; + position_t m_Position; +}; +static_assert(sizeof(MemoryFileStream) == 0x20); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_Util.h b/include/nn/atk/detail/util/atk_Util.h new file mode 100644 index 0000000..df86047 --- /dev/null +++ b/include/nn/atk/detail/util/atk_Util.h @@ -0,0 +1,207 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk { +class SoundArchive; +class SoundArchivePlayer; +class OutputReceiver; + +namespace detail { +class PlayerHeapDataManager; +class SoundArchiveLoader; +struct LoadItemInfo; +struct Util { + NN_NO_COPY(Util); + NN_NO_MOVE(Util); + + constexpr static s32 VolumeDbMin = -904; + constexpr static s32 VolumeDbMax = 60; + + constexpr static s32 PitchDivisionBit = 0b1000; + constexpr static s32 PitchDivisionRange = 256; + + constexpr static s32 CalcLpfFreqTableSize = 24; + constexpr static u32 CalcLpfFreqIntercept = 0x3E0ADE7F; + constexpr static u32 CalcLpfFreqThreshold = 0x3F666666; + + constexpr static u16 CalcLpfFreqTable[CalcLpfFreqTableSize] { + 80, 100, 128, 160, + 200, 256, 320, 400, + 500, 640, 800, 1000, + 1280, 1600, 2000, 2560, + 3200, 4000, 5120, 6400, + 8000, 10240, 12800, 16000 + }; + + constexpr static BiquadFilterCoefficients LowPassFilterCoefficientsTable32000[CalcLpfFreqTableSize] {}; + constexpr static BiquadFilterCoefficients LowPassFilterCoefficientsTable48000[CalcLpfFreqTableSize] {}; + + template + class Singleton { + public: + static Class* GetInstance(); + }; + + struct Reference { + constexpr static s32 InvalidOffset = -1; + + // Id from ElementTypes enum + u16 typeId; + u8 padding[2]; + s32 offset; + }; + static_assert(sizeof(Reference) == 0x8); + + struct ReferenceWithSize : Reference { + u32 size; + }; + static_assert(sizeof(ReferenceWithSize) == 0xc); + + struct BlockReferenceTable { + ReferenceWithSize item[1]; + }; + + struct SoundFileHeader { + BinaryFileHeader header; + BlockReferenceTable blockReferenceTable; + }; + + template + struct Table { + CountType count; + T item[1]; + }; + + struct ReferenceTable : Table {}; + struct ReferenceWithSizeTable : Table {}; + + struct BitFlag { + constexpr static u32 BitNumberMax = 31; + + u32 bitFlag; + }; + static_assert(sizeof(BitFlag) == 0x4); + + enum PanCurve { + PanCurve_Sqrt, + PanCurve_Sincos, + PanCurve_Linear, + }; + + struct PanInfo { + PanCurve curve; + bool centerZeroFlag; + bool zeroClampFlag; + bool isEnableFrontBypass; + }; + static_assert(sizeof(PanInfo) == 0x8); + + enum WaveArchiveLoadStatus { + WaveArchiveLoadStatus_Error = -2, + WaveArchiveLoadStatus_NotYet, + WaveArchiveLoadStatus_Ok, + WaveArchiveLoadStatus_Noneed, + WaveArchiveLoadStatus_Partly + }; + + struct WaveId { + u32 waveArchiveId; + u32 waveIndex; + }; + static_assert(sizeof(WaveId) == 0x8); + + struct WaveIdTable { + Table table; + }; + + class WarningLogger { + public: + enum LogId { + LogId_ChannelAllocationFailed, + LogId_SoundthreadFailedWakeup, + LogId_LogbufferFull, + LogId_Max, + }; + + struct LogBuffer { + constexpr static u32 LogCount = 64; + + struct Element { + + void Print(); + + s32 logId; + s32 arg0; + s32 arg1; + }; + static_assert(sizeof(Element) == 0xc); + + void Log(s32 logId, s32 arg0, s32 arg1); + void Print(); + + Element element[LogCount]; + s32 counter; + }; + static_assert(sizeof(LogBuffer) == 0x304); + + void Log(s32 logId, s32 arg0, s32 arg1); + void SwapBuffer(); + void Print(); + + private: + LogBuffer m_Buffer0; + LogBuffer m_Buffer1; + LogBuffer* m_pCurrentBuffer; + }; + static_assert(sizeof(WarningLogger) == 0x610); + + static u16 CalcLpfFreq(f32 scale); + static BiquadFilterCoefficients CalcLowPassFilterCoefficients(s32 frequency, s32 sampleRate, + bool isTableUsed); + + static s32 FindLpfFreqTableIndex(s32); + + static f32 CalcPanRatio(f32 pan, PanInfo* info, OutputMode mode); + static f32 CalcSurroundPanRatio(f32 surroundPan, PanInfo* info); + static f32 CalcPitchRatio(f32 pitch_); + static f32 CalcVolumeRatio(f32 dB); + static f32 CalcRandom(); + + static void* GetWaveFile(u32, u32, const SoundArchive&, const SoundArchivePlayer&); + static void* GetWaveFile(u32, u32, const SoundArchive&, const PlayerHeapDataManager&); + + static WaveArchiveLoadStatus GetWaveArchiveOfBank(const LoadItemInfo& warcLoadInfo, + bool& isLoadIndividual, const void* bankFile, + const SoundArchive& arc, const SoundArchiveLoader& mgr); + + static void* GetWaveFileOfWaveSound(const void* wsdFile, u32 index, + const SoundArchive& arc, const SoundArchiveLoader& mgr); + + static s32 GetOutputReceiverMixBufferIndex(OutputReceiver*, s32, s32); + + static size_t GetSampleByByte(size_t samples, SampleFormat format); + static size_t GetByteBySample(size_t samples, SampleFormat format); + + static bool IsValidMemoryForDsp(const void* ptr, size_t size); +}; + +static const f32 NoteTable[12] {}; +static const f32 PitchTable[Util::PitchDivisionRange] {}; +static const f32 Decibel2RatioTable[965] {}; + +static const f32 Pan2RatioTableSqrtSurround[257] {}; +static const f32 Pan2RatioTableSinCosSurround[257] {}; +static const f32 Pan2RatioTableLinearSurround[257] {}; + +static const f32 Pan2RatioTableSqrt[257] {}; +static const f32 Pan2RatioTableSinCos[257] {}; +static const f32 Pan2RatioTableLinear[257] {}; + +static const f32* PanTableTable[3] {Pan2RatioTableSqrt, Pan2RatioTableSinCos, Pan2RatioTableLinear}; +static const f32* PanTableTableForSurround[3] {Pan2RatioTableSqrtSurround, Pan2RatioTableSinCosSurround, Pan2RatioTableLinearSurround}; +} // namespace nn::atk::detail +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_WavBinary.h b/include/nn/atk/detail/util/atk_WavBinary.h new file mode 100644 index 0000000..0bea094 --- /dev/null +++ b/include/nn/atk/detail/util/atk_WavBinary.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail { +struct ChunkHeader { + u32 id; + fnd::PcBinU32 size; +}; +static_assert(sizeof(ChunkHeader) == 0x8); + +struct RiffChunk { + ChunkHeader header; + u32 formatType; +}; +static_assert(sizeof(RiffChunk) == 0xc); + +struct FmtChunk { + ChunkHeader header; + fnd::PcBinU16 formatTag; + fnd::PcBinU16 channels; + fnd::PcBinU32 samplesPerSec; + fnd::PcBinU32 avgBytesPerSec; + fnd::PcBinU16 blockAlign; + fnd::PcBinU16 bitsPerSample; +}; +static_assert(sizeof(FmtChunk) == 0x18); + +struct DataChunk { + ChunkHeader header; +}; +static_assert(sizeof(DataChunk) == 0x8); + +struct WaveBinaryHeader { + RiffChunk riffChunk; + FmtChunk fmtChunk; + DataChunk dataChunk; +}; +static_assert(sizeof(WaveBinaryHeader) == 0x2c); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/util/atk_WavOutFileStream.h b/include/nn/atk/detail/util/atk_WavOutFileStream.h new file mode 100644 index 0000000..b730624 --- /dev/null +++ b/include/nn/atk/detail/util/atk_WavOutFileStream.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class WavOutFileStream { +public: + constexpr static u8 FileIoBufferAlignment = 8; + + WavOutFileStream(); + ~WavOutFileStream(); + + bool Open(fnd::FileStream& stream, s32, u64); + + bool WriteHeader(s32, u64); + + void Close(); + + bool FlushBuffer(); + + u64 CalcRiffChunkSize(u64); + + bool UpdateRiffChunkSize(); + bool UpdateDataChunkSize(); + + size_t Write(const void* buffer, size_t size); + size_t WriteDirect(const void* buf, size_t length, fnd::FndResult* result); + + bool Seek(position_t offset, fnd::Stream::SeekOrigin origin); + + void SetCacheBuffer(char* cacheBuffer, size_t cacheBufferSize); + +private: + fnd::FileStream* m_pFileStream; + size_t m_WaveDataSize; + bool m_IsWaveDataSizeCalculating; + char* m_Buffer; + size_t m_BufferLength; + size_t m_ValidBufferLength; +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_Channel.h b/include/nn/atk/detail/voice/atk_Channel.h new file mode 100644 index 0000000..69424c8 --- /dev/null +++ b/include/nn/atk/detail/voice/atk_Channel.h @@ -0,0 +1,157 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace nn::atk::detail::driver { +class ChannelManager; + +class Channel { +public: + enum ChannelCallbackStatus { + ChannelCallbackStatus_Stopped, + ChannelCallbackStatus_Drop, + ChannelCallbackStatus_Finish, + ChannelCallbackStatus_Cancel, + }; + + enum LfoTarget { + LfoTarget_Pitch, + LfoTarget_Volume, + LfoTarget_Pan, + LfoTarget_Invalid = 0xff, + }; + + using ChannelCallback = void(*)(Channel*,ChannelCallbackStatus,void*); + + constexpr static u32 ChannelCount = 97; + constexpr static u32 ChannelMin = 0; + constexpr static u32 ChannelMax = 96; + + constexpr static u32 PriorityRelease = 1; + + constexpr static u32 KeyInit = 60; + constexpr static u32 OriginalKeyInit = KeyInit; + + constexpr static u8 SilenceVolumeMax = 255; + constexpr static u8 SilenceVolumeMin = 0; + + constexpr static u32 WaveBufferMax = 2; + + constexpr static u32 ModCount = 4; + + constexpr static f32 SilenceVolumeMaxR = 1.0 / SilenceVolumeMax; + + class Disposer : DisposeCallback { + public: + ~Disposer() override; + + void InvalidateData(const void* start, const void* end) override; + + private: + Channel* m_pChannel; + }; + + Channel(); + ~Channel(); + + void InitParam(ChannelCallback callback, void* callbackData); + + void Update(bool doPeriodicProc); + void Stop(); + + s32 GetSweepValue() const; + void UpdateSweep(s32 count); + + void Start(const WaveInfo& waveInfo, s32 length, position_t startOffsetSamples); + void Start(const WaveInfo& waveInfo, s32 length, position_t startOffsetSamples, + bool isContextCalculationSkipMode); + + void AppendWaveBuffer(const WaveInfo& waveInfo, position_t startOffsetSamples); + void AppendWaveBuffer(const WaveInfo& waveInfo, position_t startOffsetSamples, + bool isContextCalculationSkipMode); + + void Release(); + + void NoteOff(); + + void SetSweepParam(f32 sweepPitch, s32 sweepTime, bool autoUpdate); + void SetBiquadFilter(s32 type, f32 value); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void SetTvAdditionalParam(OutputAdditionalParam* param); +#endif + + position_t GetCurrentPlayingSample(bool) const; + + static void VoiceCallbackFunc(MultiVoice* voice, + MultiVoice::VoiceCallbackStatus status, void* arg); + + void CallChannelCallback(ChannelCallbackStatus status); + + static Channel* AllocChannel(s32 voiceChannelCount, s32 priority, + ChannelCallback callback, void* callbackData); + + void FreeChannel(); + void DetachChannel(); + +private: + friend ChannelManager; + + Disposer m_Disposer; + CurveAdshr m_CurveAdshr; + CurveLfo m_Lfo[4]; + u8 m_LfoTarget[4]; + u8 m_PauseFlag; + u8 m_ActiveFlag; + u8 m_AllocFlag; + u8 m_AutoSweep; + u8 m_ReleasePriorityFixFlag; + u8 m_IsIgnoreNoteOff; + u8 m_BiquadType; + u8 m_Padding[1]; + f32 m_UserVolume; + f32 m_UserPitchRatio; + f32 m_UserLpfFreq; + f32 m_BiquadValue; + u32 m_OutputLineFlag; + OutputParam m_TvParam; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + detail::OutputAdditionalParam* m_pTvAdditionalParam; +#endif + f32 m_UserPitch; + f32 m_SweepPitch; + s32 m_SweepCounter; + s32 m_SweepLength; + f32 m_InitPan; + f32 m_InitSurroundPan; + f32 m_Tune; + MoveValue m_SilenceVolume; + f32 m_Cent; + f32 m_CentPitch; + s32 m_Length; + PanMode m_PanMode; + PanCurve m_PanCurve; + u8 m_Key; + u8 m_OriginalKey; + u8 m_KeyGroupId; + u8 m_InterpolationType; + f32 m_InstrumentVolume; + f32 m_Velocity; + ChannelCallback m_Callback; + void* m_CallbackData; + MultiVoice* m_pVoice; + Channel* m_pNextLink; + WaveBuffer m_WaveBuffer[2][2]; + AdpcmContext m_AdpcmContext[2]; + AdpcmContext m_AdpcmLoopContext[2]; + position_t m_LoopStartFrame; + position_t m_OriginalLoopStartFrame; + bool m_LoopFlag; + util::IntrusiveListNode m_Link; +}; +static_assert(sizeof(Channel) == 0x400); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_ChannelManager.h b/include/nn/atk/detail/voice/atk_ChannelManager.h new file mode 100644 index 0000000..20268b1 --- /dev/null +++ b/include/nn/atk/detail/voice/atk_ChannelManager.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail::driver { +class ChannelManager { +public: + using ChannelPool = InstancePool; + using ChannelList = util::IntrusiveList>; + + ChannelManager(); + + size_t GetObjectSize(const SoundInstanceConfig& config); + size_t GetRequiredMemSize(s32 channelCount, const SoundInstanceConfig& config); + + void Initialize(void* mem, size_t memSize, s32 channelCount, const SoundInstanceConfig& config); + void Finalize(); + + void Free(Channel* channel); + + Channel* Alloc(); + + void UpdateAllChannel(); + void UpdateAudioFrameChannel(); + +private: + ChannelPool m_Pool; + ChannelList m_ChannelList; + bool m_IsInitialized; + s32 m_ChannelCount; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + InstancePool* m_pAdditionalParamPool; + BufferPool* m_pAdditionalParamBufferPool; + size_t m_AdditionalParamBufferSizePerChannel; + SoundInstanceConfig m_SoundInstanceConfig; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(ChannelManager) == 0x30); +#else +static_assert(sizeof(ChannelManager) == 0x50); +#endif +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_LowLevelVoice.h b/include/nn/atk/detail/voice/atk_LowLevelVoice.h new file mode 100644 index 0000000..5b2cebc --- /dev/null +++ b/include/nn/atk/detail/voice/atk_LowLevelVoice.h @@ -0,0 +1,117 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace nn::atk::detail { +class Voice; + +class alignas(256) LowLevelVoice { +public: + LowLevelVoice(); + + void Initialize(); + void Finalize(); + + void FreeAllWaveBuffer(); + + bool IsAvailable() const; + void SetAvailable(bool isAvailable); + + bool IsVoiceDroppedFlagOn() const; + + void AppendWaveBuffer(WaveBuffer* waveBuffer); + + void UpdateState(OutputMode outputMode); + void UpdateStatePlay(bool isRun, OutputMode outputMode); + void UpdateStateStop(bool isRun); + void UpdateStatePause(bool isRun, OutputMode outputMode); + + void SetPriority(s32 priority); + + bool AllocVoice(); + + void SetState(VoiceState state); + + void UpdateVoiceInfo(VoiceInfo* voiceInfo) const; + void UpdateVoiceParam(const VoiceParam& voiceParam, OutputMode outputMode); + void UpdateVolume(const VoiceParam& voiceParam); + void UpdatePitch(const VoiceParam& voiceParam); + void UpdateBiquadFilter(const VoiceParam& voiceParam); + void UpdateLowPassFilter(const VoiceParam& voiceParam); + void UpdateMixVolume(const OutputMix& outputMix, OutputMode outputMode); + void UpdateWaveBuffer(bool isRun, OutputMode outputMode); + void UpdatePlayPosition(); + void UpdateWaveBufferOnPlayState(); + void UpdateWaveBufferOnStopState(OutputMode outputMode); + + bool AppendWaveBufferToVoice(WaveBuffer* waveBuffer); + + void UpdateMixVolumeOnSubMix(const OutputMix& outputMix, OutputMode outputMode); + void UpdateMixVolumeOnFinalMix(const OutputMix& outputMix, OutputMode outputMode); + + static f32 GetClampedVoiceVolume(f32 volume); + + void SetVoiceMixVolume(f32 volume, s32 dstIndex); + +private: + AdpcmParam m_AdpcmParam; + audio::VoiceType m_Voice; + bool m_IsAvailable; + bool m_IsSetVoiceSlot; + VoiceParam m_VoiceParam; + s32 m_Priority; + VoiceState m_State; + u32 m_SampleRate; + SampleFormat m_SampleFormat; + position_t m_PlayPosition; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void* _c0; // 0xc0 +#else + OutputReceiver* m_pOutputReceiver; +#endif + WaveBuffer* m_WaveBufferListBegin; + WaveBuffer* m_WaveBufferListEnd; + WaveBuffer* m_LastAppendBuffer; + Voice* m_pVoice; + audio::NodeId nodeId; +}; +static_assert(sizeof(LowLevelVoice) == 0x100); + +class LowLevelVoiceAllocator { +public: + constexpr static u32 Unassigned = -1; + + LowLevelVoiceAllocator(); + + size_t GetRequiredMemSize(s32 voiceCount); + + void Initialize(s32 voiceCount, void* mem, size_t memSize); + void Finalize(); + + void UpdateAllVoiceState(OutputMode outputMode); + + LowLevelVoice* AllocVoice(); + u64 GetVoiceArrayIndex(LowLevelVoice* pVoice); + void FreeVoice(LowLevelVoice* pVoice); + + s32* GetDroppedVoiceCount() const; + +private: + void* m_pVoiceArray{}; + LowLevelVoice** m_ppVoiceTable{}; + s32 m_UsingCount{0}; + s32* m_pAssignedTableIndex{}; + s32 m_VoiceCount{}; + std::atomic m_DroppedVoiceCount{0}; +}; +static_assert(sizeof(LowLevelVoiceAllocator) == 0x28); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_MultiVoice.h b/include/nn/atk/detail/voice/atk_MultiVoice.h new file mode 100644 index 0000000..7c24b5e --- /dev/null +++ b/include/nn/atk/detail/voice/atk_MultiVoice.h @@ -0,0 +1,198 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk::detail::driver { +class MultiVoiceManager; + +class MultiVoice { +public: + struct PreMixVolume { + f32 volume[24]; + }; + static_assert(sizeof(PreMixVolume) == 0x60); + + enum VoiceCallbackStatus { + VoiceCallbackStatus_FinishWave, + VoiceCallbackStatus_Cancel, + VoiceCallbackStatus_DropVoice, + VoiceCallbackStatus_DropDsp, + }; + + using VoiceCallback = void(*)(MultiVoice*,VoiceCallbackStatus,void*); + + constexpr static u32 UpdateStart = 0b0000001; + constexpr static u32 UpdatePause = 0b0000010; + constexpr static u32 UpdateSrc = 0b0000100; + constexpr static u32 UpdateMix = 0b0001000; + constexpr static u32 UpdateLpf = 0b0010000; + constexpr static u32 UpdateBiquad = 0b0100000; + constexpr static u32 UpdateVe = 0b1000000; + + constexpr static u32 PriorityNoDrop = 255; + + constexpr static f32 VolumeMin = 0.0; + constexpr static f32 VolumeDefault = 1.0; + constexpr static f32 VolumeMax = 2.0; + + constexpr static f32 PanLeft = -1.0; + constexpr static f32 PanCenter = 0.0; + constexpr static f32 PanRight = 1.0; + + constexpr static f32 SpanFront = 0.0; + constexpr static f32 SpanCenter = 1.0; + constexpr static f32 SpanRear = 2.0; + + constexpr static f32 CutoffFreqMin = 0.0; + constexpr static f32 CutoffFreqMax = 1.0; + + constexpr static f32 BiquadValueMin = 0.0; + constexpr static f32 BiquadValueMax = 1.0; + + constexpr static f32 SendMin = 0.0; + constexpr static f32 SendMax = 1.0; + + explicit MultiVoice(); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + explicit MultiVoice(OutputAdditionalParam* pAdditionalParam); +#endif + ~MultiVoice(); + + bool Alloc(s32 channelCount, s32 priority, VoiceCallback callback, void* callbackData); + void InitParam(VoiceCallback callback, void* callbackData); + void Free(); + + void Start(); + void Stop(); + void StopAllSdkVoice(); + + void UpdateVoiceStatus(); + + bool IsPlayFinished() const; + + void Pause(bool flag); + + void Calc(); + void CalcSrc(bool); + void CalcVe(); + void CalcMix(); + void CalcLpf(); + void CalcBiquadFilter(); + + void Update(); + + void RunAllSdkVoice(); + void PauseAllSdkVoice(); + + void SetSampleFormat(SampleFormat format); + void SetSampleRate(s32 sampleRate); + void SetVolume(f32 volume); + void SetPitch(f32 pitch); + void SetPanMode(PanMode panMode); + void SetPanCurve(PanCurve panCurve); + void SetLpfFreq(f32 lpfFreq); + void SetBiquadFilter(s32 type, f32 value); + void SetPriority(s32 priority); + void SetOutputLine(u32 lineFlag); + void SetOutputParamImpl(const OutputParam& in, const OutputParam& out); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void SetOutputAdditionalParamImpl(const SendArray* pAdditionalSend, + const BusMixVolumePacket* pBusMixVolumePacket, + const OutputBusMixVolume* pBusMixVolume, + const VolumeThroughModePacket* pVolumeThroughModePacket); +#endif + void SetOutputBusMixVolumeImpl(const BusMixVolumePacket& in, + const OutputBusMixVolume& busMixVolume, + const BusMixVolumePacket& out); + void SetOutputVolumeThroughModePacketImpl(const VolumeThroughModePacket&, + const VolumeThroughModePacket&); + void SetTvParam(const OutputParam& param); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void SetTvAdditionalParam(const OutputAdditionalParam& param); + void SetTvAdditionalParam(const SendArray* pAdditionalSend, + const BusMixVolumePacket* pBusMixVolumePacket, + const OutputBusMixVolume* pBusMixVolume, + const VolumeThroughModePacket* pVolumeThroughModePacket); + void SetOutputReceiver(OutputReceiver* pOutputReceiver); +#endif + void SetSubMixIndex(s32 subMixIndex); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void CalcPreMixVolume(PreMixVolume* mix, const OutputParam& param, + s32 channelIndex, OutputDevice device); +#else + void CalcPreMixVolume(PreMixVolume* mix, const OutputParam& param, + OutputAdditionalParam* pAdditionalParam, s32 channelIndex, + OutputDevice device); +#endif + void CalcTvMix(OutputMix* mix, const PreMixVolume& pre); + void CalcMixImpl(OutputMix* mix, u32 outputDeviceIndex, + const OutputParam& param, const PreMixVolume& pre); +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + void CalcMixImpl(OutputMix* mix, u32 outputDeviceIndex, const OutputParam& param, + OutputAdditionalParam* pAdditionalParam, const PreMixVolume& pre); +#endif + + MultiVoice* detail_GetSdkVoice(s32) const; + + position_t GetCurrentPlayingSample() const; + SampleFormat GetFormat() const; + + bool IsRun() const; + + void SetInterpolationType(u8 interpolationType); + + void AppendWaveBuffer(s32 channelIndex, WaveBuffer* pBuffer, bool lastFlag); + + void SetAdpcmParam(s32 channelIndex, const AdpcmParam& param); + + static u64 FrameToByte(s64, SampleFormat); + static void CalcOffsetAdpcmParam(AdpcmContext* context, const AdpcmParam& param, + position_t offsetSamples, const void* dataAddress); + +private: + friend MultiVoiceManager; + + Voice m_Voice[2]; + s32 m_ChannelCount; + VoiceCallback m_Callback; + void* m_pCallbackData; + bool m_IsActive; + bool m_IsStart; + bool m_IsStarted; + bool m_IsPause; + bool m_IsPausing; + bool m_IsInitialized; + WaveBuffer* m_pLastWaveBuffer; + u16 m_SyncFlag; + u8 m_BiquadType; + bool m_IsEnableFrontBypass; + f32 m_Volume; + f32 m_Pitch; + PanMode m_PanMode; + PanCurve m_PanCurve; + f32 m_LpfFreq; + f32 m_BiquadValue; + s32 m_Priority; + u32 m_OutputLineFlag; + OutputParam m_TvParam; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputAdditionalParam* m_pTvAdditionalParam; +#endif + SampleFormat m_Format; + std::uintptr_t m_VoiceUser; + UpdateType m_UpdateType; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* m_pOutputReceiver; +#endif + util::IntrusiveListNode m_LinkNode; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(MultiVoice) == 0x270); +#else +static_assert(sizeof(MultiVoice) == 0x298); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_MultiVoiceManager.h b/include/nn/atk/detail/voice/atk_MultiVoiceManager.h new file mode 100644 index 0000000..dedc900 --- /dev/null +++ b/include/nn/atk/detail/voice/atk_MultiVoiceManager.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +namespace nn::atk::detail::driver { +class MultiVoiceManager { +public: + using VoiceList = util::IntrusiveList>; + + MultiVoiceManager(); + + size_t GetObjectSize(const SoundInstanceConfig& config); + size_t GetRequiredMemSize(s32 voiceCount, const SoundInstanceConfig& config); + + void Initialize(void* mem, size_t memSize, const SoundInstanceConfig& config); + void Finalize(); + + void StopAllVoices(); + + MultiVoice* AllocVoice(s32 voiceChannelCount, s32 priority, + MultiVoice::VoiceCallback callback, void* callbackData); + + bool DropLowestPriorityVoice(s32); + + void AppendVoiceList(MultiVoice* voice); + + void FreeVoice(MultiVoice* voice); + + void RemoveVoiceList(MultiVoice* voice); + + void UpdateAllVoiceStatus(); + void UpdateAudioFrameVoiceStatus(); + void UpdateAllVoices(); + void UpdateAudioFrameVoices(); + + void ChangeVoicePriority(MultiVoice* voice); + + void UpdateAllVoicesSync(u32 syncFlag); + + s32 GetVoiceCount() const; + s32 GetActiveCount() const; + s32 GetFreeCount() const; + + VoiceList* GetVoiceList() const; + +private: + bool m_Initialized; + VoiceList m_PrioVoiceList; + VoiceList m_FreeVoiceList; +}; +static_assert(sizeof(MultiVoiceManager) == 0x28); +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_Voice.h b/include/nn/atk/detail/voice/atk_Voice.h new file mode 100644 index 0000000..1d02a0f --- /dev/null +++ b/include/nn/atk/detail/voice/atk_Voice.h @@ -0,0 +1,92 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk::detail { +class Voice { +public: + constexpr static s32 PriorityMin = 0; + constexpr static s32 PriorityMax = 255; + constexpr static s32 PriorityNoDrop = 255; + + Voice(); + ~Voice(); + + void Initialize(u32); + + bool IsAvailable() const; + + bool AllocVoice(u32 priority); + void Free(); + + void SetPriority(u32 priority); + void SetState(VoiceState state); + + void AppendWaveBuffer(WaveBuffer* waveBuffer); + + void FreeAllWaveBuffer(); + + void UpdateParam(); + + position_t GetPlayPosition() const; + + bool SetMonoFilter(bool enable, u16 cutoff); + void SetBiquadFilter(bool enable, const BiquadFilterCoefficients* coef); + + void UpdateVoiceStatus(); + +private: + u32 m_Priority; + VoiceState m_State; + VoiceParam m_VoiceParam; + SampleFormat m_SampleFormat; + u32 m_SampleRate; + AdpcmParam m_AdpcmParam; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + s32 m_SubMixIndex; +#else + OutputReceiver* m_pOutputReceiver; +#endif + u32 m_VoiceId; + position_t m_PlayPosition; + u32 m_VoiceInfoEnableFlag; + u32 m_CommandTag; + WaveBuffer* m_WaveBufferListBegin; + WaveBuffer* m_WaveBufferListEnd; + LowLevelVoice* m_pLowLevelVoice; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(Voice) == 0xd8); +#else +static_assert(sizeof(Voice) == 0xe0); +#endif + +class VirtualVoiceManager : Util::Singleton { +public: + constexpr static s32 InvalidVoiceId = -1; + + constexpr static u32 VirtualVoiceCount = 256; + constexpr static u32 VirtualVoiceElementCount = 8; + + void Initialize(); + + bool AllocVirtualVoice(); + void FreeVirtualVoice(u32); + + void UpdateVoiceInfo(); + + s32 GetAllocatedVirtualVoiceCount() const; + s32 GetUnreleasedLowLevelVoiceCount() const; + +private: + u32 m_VirtualVoiceAllocationTable[VirtualVoiceElementCount]; + u32 m_VoiceInfoTableRead; + LowLevelVoice* m_LowLevelVoiceTable[VirtualVoiceCount]; + VoiceInfo m_VoiceInfoTable[2][VirtualVoiceCount]; + util::BitFlagSet m_VoiceInfoDirtyTable[2]; +}; +static_assert(sizeof(VirtualVoiceManager) == 0x4868); +} // namespace nn::atk::voice \ No newline at end of file diff --git a/include/nn/atk/detail/voice/atk_VoiceCommand.h b/include/nn/atk/detail/voice/atk_VoiceCommand.h new file mode 100644 index 0000000..431426e --- /dev/null +++ b/include/nn/atk/detail/voice/atk_VoiceCommand.h @@ -0,0 +1,96 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk::detail { +struct VoiceCommandPlay : Command { + u32 voiceId; + SampleFormat sampleFormat; + u32 sampleRate; + AdpcmParam adpcmParam; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + OutputReceiver* pOutputReceiver; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(VoiceCommandPlay) == 0x48); +#else +static_assert(sizeof(VoiceCommandPlay) == 0x50); +#endif + +struct VoiceCommandPause : Command { + u32 voiceId; +}; +static_assert(sizeof(VoiceCommandPause) == 0x20); + +struct VoiceCommandFree : Command { + u32 voiceId; +}; +static_assert(sizeof(VoiceCommandFree) == 0x20); + +struct VoiceCommandParam : Command { + u32 voiceId; + VoiceParam voiceParam; +}; +static_assert(sizeof(VoiceCommandParam) == 0x98); + +struct VoiceCommandPriority : Command { + u32 voiceId; + u32 priority; +}; +static_assert(sizeof(VoiceCommandPriority) == 0x20); + +struct VoiceCommandAlloc : Command { + u32 voiceId; + u32 priority; + void* userId; +}; +static_assert(sizeof(VoiceCommandAlloc) == 0x28); + +struct VoiceCommandAppendWaveBuffer : Command { + u32 voiceId; + void* tag; + void* bufferAddress; + size_t bufferSize; + size_t sampleLength; + position_t sampleOffset; + bool adpcmContextEnable; + AdpcmContext adpcmContext; + bool loopFlag; +}; +static_assert(sizeof(VoiceCommandAppendWaveBuffer) == 0x100); + +class VoiceReplyCommand : CommandManager { +public: + static void ProcessCommandList(Command* commandList); + +}; +static_assert(sizeof(VoiceReplyCommand) == 0x310); + +class LowLevelVoiceCommand : CommandManager { +public: + struct WaveBufferPacket { + AdpcmContext adpcmContext; + WaveBuffer waveBuffer; + }; + static_assert(sizeof(WaveBufferPacket) == 0x80); + + void Initialize(void*, size_t, void*, size_t, s32); + + static void ProcessCommandList(Command* commandList); + + static size_t GetRequiredWaveBufferMemSize(s32); + + static void LowLevelVoiceDisposeCallback(LowLevelVoice*, void*); + + void* GetFreeWaveBuffer(); + +private: + WaveBufferPacket* m_pWaveBufferPacket; + s32 m_WaveBufferPacketCount; +}; +static_assert(sizeof(LowLevelVoiceCommand) == 0x320); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSound.h b/include/nn/atk/detail/wsd/atk_WaveSound.h new file mode 100644 index 0000000..7390f90 --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSound.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include + +namespace nn::atk::detail { +class WaveSound; +using WaveSoundInstanceManager = SoundInstanceManager; + +class WaveSound : BasicSound { +public: + explicit WaveSound(WaveSoundInstanceManager& manager); + ~WaveSound() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void Prepare(const void* wsdFile, const void* waveFile, + const driver::WaveSoundPlayer::StartInfo& startInfo, s8 waveType); + + void RegisterDataLoadTask(const driver::WaveSoundLoader::LoadInfo& loadInfo, + const driver::WaveSoundPlayer::StartInfo& startInfo); + + void SetChannelPriority(s32 priority); + + void InitializeChannelParam(s32 priority, bool isReleasePriorityFix); + + void OnUpdatePlayerPriority() override; + + bool IsAttachedTempSpecialHandle() override; + void DetachTempSpecialHandle() override; + + bool ReadWaveSoundDataInfo(WaveSoundDataInfo*) const; + + position_t GetPlaySamplePosition(bool) const; + + bool IsPrepared() const override; + + driver::BasicSoundPlayer* GetBasicSoundPlayerHandle() override; + + void OnUpdateParam() override; + +private: + friend WaveSoundInstanceManager; + + util::IntrusiveListNode m_PriorityLink; + WaveSoundHandle* m_pTempSpecialHandle; + WaveSoundInstanceManager* m_Manager; + void* m_pWaveFile; + s8 m_WaveType; + bool m_InitializeFlag; + bool m_IsCalledPrepare; + u8 m_Padding[1]; + u32 m_ChannelCount; + driver::WaveSoundPlayer m_PlayerInstance; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(WaveSound) == 0x3b0); +#else +static_assert(sizeof(WaveSound) == 0x3e0); +#endif +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSoundFile.h b/include/nn/atk/detail/wsd/atk_WaveSoundFile.h new file mode 100644 index 0000000..2276947 --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSoundFile.h @@ -0,0 +1,92 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct WaveSoundFile { + struct InfoBlock; + struct FileHeader : Util::SoundFileHeader { + + InfoBlock* GetInfoBlock() const; + + }; + + struct WaveSoundData; + struct InfoBlockBody { + + WaveSoundData* GetWaveSoundData(u32 index) const; + Util::ReferenceTable* GetWaveSoundDataReferenceTable() const; + + Util::WaveIdTable* GetWaveIdTable() const; + + Util::Reference toWaveIdTable; + Util::Reference toWaveSoundDataReferenceTable; + }; + static_assert(sizeof(InfoBlockBody) == 0x10); + + struct InfoBlock { + BinaryBlockHeader header; + InfoBlockBody body; + }; + static_assert(sizeof(InfoBlock) == 0x18); + + struct WaveSoundInfo; + struct TrackInfo; + struct NoteInfo; + struct WaveSoundData { + + WaveSoundInfo* GetWaveSoundInfo() const; + + Util::ReferenceTable* GetTrackInfoReferenceTable() const; + Util::ReferenceTable* GetNoteInfoReferenceTable() const; + + TrackInfo* GetTrackInfo(u32 index) const; + NoteInfo* GetNoteInfo(u32 index) const; + + Util::Reference toWaveSoundInfo; + Util::Reference toTrackInfoReferenceTable; + Util::Reference toNoteInfoReferenceTable; + }; + static_assert(sizeof(WaveSoundData) == 0x18); + + struct WaveSoundInfo { + + u8 GetPan() const; + s8 GetSurroundPan() const; + f32 GetPitch() const; + void GetSendValue(u8* mainSend, u8* fxSend, u8 fxSendCount) const; + AdshrCurve* GetAdshrCurve() const; + u8 GetLpfFreq() const; + u8 GetBiquadType() const; + u8 GetBiquadValue() const; + + Util::BitFlag optionParameter; + }; + static_assert(sizeof(WaveSoundInfo) == 0x4); + + struct NoteEvent; + struct TrackInfo { + + Util::ReferenceTable* GetNoteEventReferenceTable() const; + NoteEvent* GetNoteEvent(u32 index) const; + + Util::Reference toNoteEventReferenceTable; + }; + static_assert(sizeof(TrackInfo) == 0x8); + + struct NoteInfo { + + u8 GetOriginalKey() const; + u8 GetVolume() const; + u8 GetPan() const; + u8 GetSurroundPan() const; + f32 GetPitch() const; + f32 GetSendValue(u8*, u8**, u8) const; + AdshrCurve* GetAdshrCurve() const; + + u32 waveIdTableIndex; + Util::BitFlag optionParameter; + }; + static_assert(sizeof(NoteInfo) == 0x8); +}; +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSoundFileReader.h b/include/nn/atk/detail/wsd/atk_WaveSoundFileReader.h new file mode 100644 index 0000000..5416b72 --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSoundFileReader.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +namespace nn::atk::detail { +struct WaveSoundInfo { + f32 pitch; + AdshrCurve adshr; + u8 pan; + u8 surroundPan; + u8 mainSend; + u8 fxSend[3]; + u8 lpfFreq; + u8 biquadType; + u8 biquadValue; +}; +static_assert(sizeof(WaveSoundInfo) == 0x14); + +struct WaveSoundNoteInfo { + u32 waveArchiveId; + s32 waveIndex; + AdshrCurve adshr; + u8 originalKey; + u8 pan; + u8 surroundPan; + u8 volume; + f32 pitch; +}; +static_assert(sizeof(WaveSoundNoteInfo) == 0x18); + +class WaveSoundFileReader { +public: + constexpr static s32 SignatureFile = 0x44535746; // FWSD + + explicit WaveSoundFileReader(const void* waveSoundFile); + + s32 GetWaveSoundCount() const; + s32 GetNoteInfoCount(u32) const; + s32 GetTrackInfoCount(u32) const; + + bool ReadWaveSoundInfo(WaveSoundInfo* dst, u32 index) const; + + bool IsFilterSupportedVersion() const; + + bool ReadNoteInfo(WaveSoundNoteInfo* dst, u32 index, u32 noteIndex) const; + +private: + WaveSoundFile::FileHeader* m_pHeader; + WaveSoundFile::InfoBlockBody* m_pInfoBlockBody; +}; +static_assert(sizeof(WaveSoundFileReader) == 0x10); +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSoundLoader.h b/include/nn/atk/detail/wsd/atk_WaveSoundLoader.h new file mode 100644 index 0000000..581ffc1 --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSoundLoader.h @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace nn::atk::detail::driver { +class WaveSoundLoader; +using WaveSoundLoaderManager = LoaderManager; + +class WaveSoundLoader { +public: + struct Arg { + SoundArchive* soundArchive; + SoundDataManager* soundDataManager; + SoundPlayer* soundPlayer; + LoadItemInfo loadInfoWsd; + s32 index; + }; + static_assert(sizeof(Arg) == 0x30); + + struct Data { + void* wsdFile; + void* waveFile; + }; + static_assert(sizeof(Data) == 0x10); + + struct LoadInfo { + SoundArchive* soundArchive; + SoundDataManager* soundDataManager; + LoadItemInfo* loadInfoWsd; + SoundPlayer* soundPlayer; + }; + static_assert(sizeof(LoadInfo) == 0x20); + + class DataLoadTask : Task { + public: + ~DataLoadTask() override; + + void Initialize(); + + bool TryAllocPlayerHeap(); + + void Execute(TaskProfileLogger& logger) override; + + private: + Arg m_Arg; + Data m_Data; + PlayerHeap* m_pPlayerHeap; + PlayerHeapDataManager* m_pPlayerHeapDataManager; + bool m_IsLoadSuccess; + u8 m_Padding[3]; + }; + static_assert(sizeof(DataLoadTask) == 0xa0); + + class FreePlayerHeapTask : Task { + public: + ~FreePlayerHeapTask() override; + + void Initialize(); + + void Execute(TaskProfileLogger& logger) override; + + private: + Arg m_Arg; + PlayerHeap* m_pPlayerHeap; + PlayerHeapDataManager* m_pPlayerHeapDataManager; + }; + + WaveSoundLoader(); + ~WaveSoundLoader(); + + void Initialize(const Arg& arg); + void Finalize(); + + bool TryWait(); + + bool IsInUse(); + +private: + friend WaveSoundLoaderManager; + + DataLoadTask m_Task; + FreePlayerHeapTask m_FreePlayerHeapTask; + PlayerHeapDataManager m_PlayerHeapDataManager; + util::IntrusiveListNode m_LinkForLoaderManager; +}; +} // namespace nn::atk::detail::driver \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSoundPlayer.h b/include/nn/atk/detail/wsd/atk_WaveSoundPlayer.h new file mode 100644 index 0000000..a62096a --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSoundPlayer.h @@ -0,0 +1,147 @@ +#pragma once + +#include +#include +#include +#include + +namespace nn::atk::detail { +struct WaveSoundDataInfo { + bool loopFlag; + s32 sampleRate; + s64 loopStart; + s64 loopEnd; + s64 compatibleLoopStart; + s64 compatibleLoopEnd; + s32 channelCount; +}; +static_assert(sizeof(WaveSoundDataInfo) == 0x30); + +namespace driver { +class WaveSoundPlayer : BasicSoundPlayer, DisposeCallback, SoundThread::PlayerCallback { +public: + enum StartOffsetType { + StartOffsetType_Sample, + StartOffsetType_Millisec, + }; + + enum ResState { + ResState_Invalid, + ResState_ReceiveLoadReq, + ResState_AppendLoadTask, + ResState_Assigned, + }; + + constexpr static s32 SignatureFile = 0x44535746; // FWSD + + constexpr static u32 PauseReleaseValue = 127; + constexpr static u32 MuteReleaseValue = 127; + constexpr static u32 DefaultPriority = 64; + + struct StartInfo { + s32 index; + StartOffsetType startOffsetType; + s32 startOffset; + s32 delayTime; + s32 delayCount; + s32 waveSoundParameterFlag; + s32 release; + bool isContextCalculationSkipMode; + UpdateType updateType; + }; + static_assert(sizeof(StartInfo) == 0x24); + + struct PrepareArg { + void* wsdFile; + void* waveFile; + s8 waveType; + u8 padding[3]; + }; + static_assert(sizeof(PrepareArg) == 0x18); + + WaveSoundPlayer(); + ~WaveSoundPlayer() override; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool Initialize() override; +#else + bool Initialize(OutputReceiver* pOutputReceiver) override; +#endif + void Finalize() override; + + void FinishPlayer(); + + void CloseChannel(); + + void FreeLoader(); + + void Prepare(const StartInfo& info, const PrepareArg& arg); + void PrepareForPlayerHeap(const PrepareArg& arg); + + void RequestLoad(const StartInfo& info, const WaveSoundLoader::Arg& arg); + + void Start() override; + void Stop() override; + void Pause(bool flag) override; + + void SetPanRange(f32 range); + void SetChannelPriority(s32 priority); + void SetReleasePriorityFix(bool fix); + + void InvalidateData(const void* start, const void* end) override; + + position_t GetPlaySamplePosition(bool) const; + + void Update(); + + bool TryAllocLoader(); + + bool StartChannel(); + void UpdateChannel(); + + static void ChannelCallbackFunc(Channel* dropChannel, + Channel::ChannelCallbackStatus status, void* userData); + + void OnUpdateFrameSoundThread() override; + void OnUpdateFrameSoundThreadWithAudioFrameFrequency() override; + void OnShutdownSoundThread() override; + +private: + bool m_WavePlayFlag; + bool m_ReleasePriorityFixFlag; + u8 m_Priority; + s8 m_WaveType; + f32 m_PanRange; + void* m_pWsdFile; + void* m_pWaveFile; + s32 m_WaveSoundIndex; + StartOffsetType m_StartOffsetType; + position_t m_StartOffset; + s32 m_DelayCount; + s32 m_Release; + s32 m_WaveSoundParameterFlag; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + bool m_IsContextCalculationSkipMode; +#endif + CurveLfoParam m_LfoParam; + WaveSoundInfo m_WaveSoundInfo; + Channel* m_pChannel; + UpdateType m_UpdateType; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + u32 m_SubMixIndex; +#endif + u8 m_ResState; + bool m_IsInitialized; + bool m_IsRegisterPlayerCallback; + u8 m_Padding[1]; + WaveSoundLoaderManager* m_pLoaderManager; + WaveSoundLoader* m_pLoader; + WaveSoundLoader::Arg m_LoaderArg; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(WaveSoundPlayer) == 0x190); +#else +static_assert(sizeof(WaveSoundPlayer) == 0x1a0); +#endif +} // namespace nn::atk::detail::driver +} // namespace nn::atk::detail \ No newline at end of file diff --git a/include/nn/atk/detail/wsd/atk_WaveSoundRuntime.h b/include/nn/atk/detail/wsd/atk_WaveSoundRuntime.h new file mode 100644 index 0000000..67f2660 --- /dev/null +++ b/include/nn/atk/detail/wsd/atk_WaveSoundRuntime.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail { +class WaveSoundRuntime { +public: + WaveSoundRuntime(); + ~WaveSoundRuntime(); + + bool Initialize(s32 soundCount, void** pOutAllocatedAddr, const void* endAddr); + void Finalize(); + + static size_t GetRequiredMemorySize(const SoundArchive::SoundArchivePlayerInfo& soundArchivePlayerInfo, + s32 alignment); + + s32 GetActiveCount() const; + s32 GetFreeWaveSoundCount() const; + + void SetupUserParam(void** startAddr, size_t adjustSize); + + void Update(); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + WaveSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo); +#else + WaveSound* AllocSound(SoundArchive::ItemId soundId, s32 priority, s32 ambientPriority, + BasicSound::AmbientInfo* ambientArgInfo, OutputReceiver* pOutputReceiver); +#endif + + SoundStartable::StartResult PrepareImpl(const SoundArchive* pSoundArchive, + const SoundDataManager* pSoundDataManager, + SoundArchive::ItemId soundId, + WaveSound* sound, + const SoundArchive::SoundInfo* commonInfo, + const StartInfoReader& startInfoReader); + + void DumpMemory(const SoundArchive*) const; + +private: + WaveSoundInstanceManager m_WaveSoundInstanceManager; + driver::WaveSoundLoaderManager m_WaveSoundLoaderManager; + SoundArchiveFilesHook* m_pSoundArchiveFilesHook; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(WaveSoundRuntime) == 0x80); +#else +static_assert(sizeof(WaveSoundRuntime) == 0x88); +#endif +} // namespace nn::atk::detail diff --git a/include/nn/atk/effect/atk_EffectAux.h b/include/nn/atk/effect/atk_EffectAux.h new file mode 100644 index 0000000..eb99b03 --- /dev/null +++ b/include/nn/atk/effect/atk_EffectAux.h @@ -0,0 +1,108 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace nn::atk { +class OutputMixer; + +class EffectAux { +public: + constexpr static s32 ChannelCountMax = 6; + + struct BufferSet { + void* sendBuffer; + void* returnBuffer; + void* readBuffer; + }; + static_assert(sizeof(BufferSet) == 0x18); + + struct UpdateSamplesArg { + s32 sampleCountPerAudioFrame; + s32 sampleRate; + s32 audioFrameCount; + s32 channelCount; + s32 readSampleCount; + OutputMode outputMode; + }; + static_assert(sizeof(UpdateSamplesArg) == 0x18); + + EffectAux(); + virtual ~EffectAux(); + virtual void Initialize(); + virtual void Finalize(); + virtual void OnChangeOutputMode(); + virtual void UpdateSamples(s32, const UpdateSamplesArg&); + + void ResetChannelIndex(); + + size_t GetRequiredMemSize(const audio::AudioRendererParameter& parameter) const; + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool AddEffect(audio::AudioRendererConfig* pConfig, + const audio::AudioRendererParameter& parameter, + audio::FinalMixType* pFinalMixType); + bool AddEffect(audio::AudioRendererConfig* pConfig, + const audio::AudioRendererParameter& parameter, + audio::SubMixType* pSubMixType); +#else + bool AddEffect(audio::AudioRendererConfig* pConfig, + const audio::AudioRendererParameter& parameter, + OutputMixer* pOutputMixer); +#endif + + void SplitEffectBuffer(BufferSet* pBufferSet, void* effectBuffer, + size_t effectBufferSize); + + void SetEffectInputOutput(const s8* input, const s8* output, s32 inputCount, s32 outputCount); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void RemoveEffect(audio::AudioRendererConfig* pConfig, audio::FinalMixType* pFinalMixType); + void RemoveEffect(audio::AudioRendererConfig* pConfig, audio::SubMixType* pSubMixType); +#else + void RemoveEffect(audio::AudioRendererConfig* pConfig, OutputMixer* pOutputMixer); +#endif + + bool SetChannelCount(s32 channelCount); + bool SetChannelIndex(const ChannelIndex* pChannel, s32 channelCount); + + s32 GetChannelCount() const; + void GetChannelIndex(ChannelIndex* pChannel, s32 channelCount) const; + + bool SetAudioFrameCount(s32 audioFrameCount); + s32 GetAudioFrameCount() const; + + bool IsRemovable() const; + bool IsClearable(); + bool IsEnabled() const; + + void SetEnabled(bool isEnabled); + void SetEffectBuffer(void* effectBuffer, size_t effectBufferSize); + + void Update(); + +private: + friend OutputMixer; + + util::IntrusiveListNode m_AuxLinkNode; + audio::AuxType m_AuxType; + std::atomic_uint64_t m_AudioRendererUpdateCountWhenAddedAux; + s32 m_AudioFrameCount; + s32 m_ChannelCount; + bool m_IsActive; + bool m_IsEnabled; + void* m_EffectBuffer; + size_t m_EffectBufferSize; + s32* m_AuxReadBuffer; + ChannelIndex m_ChannelSetting[ChannelCountMax]; +}; +static_assert(sizeof(EffectAux) == 0x50 + sizeof(ChannelIndex) * EffectAux::ChannelCountMax); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/effect/atk_EffectBase.h b/include/nn/atk/effect/atk_EffectBase.h new file mode 100644 index 0000000..ae6444c --- /dev/null +++ b/include/nn/atk/effect/atk_EffectBase.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace nn::atk { +class OutputMixer; + +class EffectBase { +public: + enum ChannelMode { + ChannelMode_1Ch, + ChannelMode_2Ch, + ChannelMode_4Ch, + ChannelMode_6Ch, + }; + + enum SampleRate { + SampleRate_32000, + SampleRate_48000, + }; + + constexpr static u8 ChannelModeCountMax = 6; + + EffectBase(); + + virtual ~EffectBase(); + virtual void unk1() = 0; + virtual void unk2() = 0; + virtual void unk3() = 0; + virtual void unk4() = 0; + virtual void unk5() = 0; + virtual void unk6() = 0; + virtual void unk7() = 0; + virtual void UpdateBuffer(s32, void**, size_t, SampleFormat, s32, OutputMode); + virtual void GetChannelIndex(ChannelIndex* pChannel, s32 channelCount) const; + virtual s32 GetChannelSettingCountMax() const; + virtual void OnChangeOutputMode(); + virtual void SetEffectBuffer(void* effectBuffer, size_t effectBufferSize); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + bool AddEffect(audio::AudioRendererConfig* pConfig, audio::FinalMixType* pFinalMixType); + bool AddEffect(audio::AudioRendererConfig* pConfig, audio::SubMixType* pFinalMixType); +#else + bool AddEffect(audio::AudioRendererConfig* pConfig, OutputMixer* pOutputMixer); +#endif + + void SetEffectInputOutput(const s8* input, const s8* output, s32 inputCount, s32 outputCount); + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void RemoveEffect(audio::AudioRendererConfig* pConfig, audio::FinalMixType* pFinalMixType); + void RemoveEffect(audio::AudioRendererConfig* pConfig, audio::SubMixType* pSubMixType); +#else + void RemoveEffect(audio::AudioRendererConfig* pConfig, OutputMixer* pOutputMixer); +#endif + + static s32 ConvertChannelModeToInt(ChannelMode channelMode); + + SampleRate GetSampleRate() const; + bool SetSampleRate(SampleRate sampleRate); + +private: + friend OutputMixer; + + util::IntrusiveListNode m_Link; + bool m_IsActive; + SampleRate m_SampleRate; + void* m_EffectBuffer; + size_t m_EffectBufferSize; +}; +static_assert(sizeof(EffectBase) == 0x30); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_Config.h b/include/nn/atk/fnd/basis/atkfnd_Config.h new file mode 100644 index 0000000..f805308 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_Config.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +using position_t = std::ptrdiff_t; +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_FrameHeapImpl.h b/include/nn/atk/fnd/basis/atkfnd_FrameHeapImpl.h new file mode 100644 index 0000000..a884dd4 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_FrameHeapImpl.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +class FrameHeapImpl : HeapBase { +public: + constexpr static s32 FreeHeadMode = 1; + constexpr static s32 FreeTailMode = 2; + constexpr static s32 FreeAllMode = 3; + + struct HeapState { + u32 tagName; + void* headAllocator; + void* tailAllocator; + HeapState* pPrevState; + }; + static_assert(sizeof(HeapState) == 0x20); + + static FrameHeapImpl* Create(void* startAddress, size_t size, u16 optFlag); + + void* Destroy(); + + void* Alloc(size_t size, s32 alignment); + void* AllocFromHead(size_t size, s32 alignment); + void* AllocFromTail(size_t size, s32 alignment); + + u64 ResizeForMBlock(void* memBlock, size_t size); + + size_t GetAllocatableSize(s32); + + void Free(s32 mode); + void FreeHead(); + void FreeTail(); + + bool RecordState(u32); + + bool FreeByState(u32); + + s32 Adjust(); + +private: + void* m_pHeadAllocator; + void* m_pTailAllocator; + HeapState* m_pState; +}; +static_assert(sizeof(FrameHeapImpl) == 0x58); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_HeapBase.h b/include/nn/atk/fnd/basis/atkfnd_HeapBase.h new file mode 100644 index 0000000..d0a83a3 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_HeapBase.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail::fnd { +class HeapBase : util::IntrusiveListBaseNode { +public: + using HeapList = util::IntrusiveList>; + + enum HeapType { + HeapType_Exp, + HeapType_Frame, + HeapType_Unit, + HeapTyep_Unknown, + }; + + enum FillType { + FillType_NoUse, + FillType_Alloc, + FillType_Free, + FillType_Max, + }; + + constexpr static u32 DefaultAlignment = 4; + + constexpr static s32 ExpHeapSignature = 0x45585048; // HPXE + constexpr static s32 FrameHeapSignature = 0x46524D48; // HMRF + constexpr static s32 UnitHeapSignature = 0x554E5448; // HTNU + + constexpr static u32 OptionZeroClear = 1; + constexpr static u32 OptionDebugFill = 1 << 1; + constexpr static u32 OptionThreadSafe = 1 << 2; + + constexpr static u32 ErrorPrint = 1; + + constexpr static u32 MIN_ALIGNMENT = 4; + + HeapList* FindListContainHeap(); + + static HeapBase* FindContainHeap(HeapList* pList, const void* memBlock); + static HeapBase* FindContainHeap(const void* memBlock); + static HeapBase* FindParentHeap(HeapBase* pChild); + + u32 SetFillValue(FillType type, u32 value); + u32 GetFillValue(FillType type); + + HeapType GetHeapType(); + + void Initialize(u32 signature, void* heapStart, void* heapEnd, u16 optFlag); + + void SetOptionFlag(u16 optFlag); + + void FillNoUseMemory(void* address, size_t size); + + void Finalize(); + + void LockHeap(); + void UnlockHeap(); + + void FillFreeMemory(void* address, size_t size); + + u16 GetOptionFlag(); + + void FillAllocMemory(void* address, size_t size); + +private: + void* mHeapStart; + void* mHeapEnd; + u32 m_Signature; + HeapList m_ChildList; + u32 m_Attribute; +}; +static_assert(sizeof(HeapBase) == 0x40); + +static u8 sFillVals[12]; +static HeapBase::HeapList sRootList {}; +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_PrimitiveTypes.h b/include/nn/atk/fnd/basis/atkfnd_PrimitiveTypes.h new file mode 100644 index 0000000..ab767f2 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_PrimitiveTypes.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +using PcBinU16 = std::uint16_t; +using PcBinU32 = std::uint32_t; +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_Result.h b/include/nn/atk/fnd/basis/atkfnd_Result.h new file mode 100644 index 0000000..74879b2 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_Result.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +enum FndResultType { + FndResultType_CodeMask = 0xffffff, + FndResultType_CategoryMask = 0x7f000000, + FndResultType_ErrorFlagMask = ~(FndResultType_CategoryMask | FndResultType_CodeMask), + + FndResultType_CategorySystem = 0x0, + FndResultType_CategoryBitOffset = 0x18, + FndResultType_CategoryIo = 0x1000000, + + FndResultType_ErrorFlag = FndResultType_ErrorFlagMask, + + FndResultType_Failed = FndResultType_ErrorFlag, + FndResultType_NotInitialized, + FndResultType_NotSupported, + FndResultType_NotOpened, + FndResultType_OutOfMemory, + FndResultType_InvalidArgument, + FndResultType_InvalidStatus, + + FndResultType_IoError = -0x7f000000, + FndResultType_IoFileNotFound, + FndResultType_IoInvalidAccess, + FndResultType_IoTargetLocked, + + FndResultType_True = 0, + FndResultType_False, +}; + +struct FndResult { + u32 value; +}; +static_assert(sizeof(FndResult) == 0x4); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_RuntimeTypeInfo.h b/include/nn/atk/fnd/basis/atkfnd_RuntimeTypeInfo.h new file mode 100644 index 0000000..5e5c206 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_RuntimeTypeInfo.h @@ -0,0 +1,10 @@ +#pragma once + +namespace nn::atk::detail::fnd { +class RuntimeTypeInfo { +public: +private: + RuntimeTypeInfo* m_ParentTypeInfo; +}; +static_assert(sizeof(RuntimeTypeInfo) == 0x8); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_ScopedLock.h b/include/nn/atk/fnd/basis/atkfnd_ScopedLock.h new file mode 100644 index 0000000..2f972fd --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_ScopedLock.h @@ -0,0 +1,9 @@ +#pragma once + +namespace nn::atk::detail::fnd { +template +class ScopedLock { +public: + LockObj* m_LockObj; +}; +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_Time.h b/include/nn/atk/fnd/basis/atkfnd_Time.h new file mode 100644 index 0000000..7cc2bbc --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_Time.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +class Time { +public: + s64 Current(); +}; + +class TimeSpan { +public: + using TickType = s64; + + static TimeSpan FromNanoSeconds(TickType); + static TimeSpan FromMicroSeconds(TickType); + static TimeSpan FromMilliSeconds(TickType); + + TickType ToNanoSeconds() const; + TickType ToMicroSeconds() const; + TickType ToMilliSeconds() const; + +private: + TickType m_TickSpan; +}; +static_assert(sizeof(TimeSpan) == 0x8); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/basis/atkfnd_WorkBufferAllocator.h b/include/nn/atk/fnd/basis/atkfnd_WorkBufferAllocator.h new file mode 100644 index 0000000..49239c6 --- /dev/null +++ b/include/nn/atk/fnd/basis/atkfnd_WorkBufferAllocator.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +class WorkBufferAllocator { +public: + WorkBufferAllocator(void* buffer, size_t size); + + void* Allocate(size_t size, size_t alignment); + void* Allocate(size_t size, size_t alignment, s32 count); + +private: + std::uintptr_t m_Buffer; + size_t m_Offset; + size_t m_Size; +}; +static_assert(sizeof(WorkBufferAllocator) == 0x18); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/io/atkfnd_FileStream.h b/include/nn/atk/fnd/io/atkfnd_FileStream.h new file mode 100644 index 0000000..967658a --- /dev/null +++ b/include/nn/atk/fnd/io/atkfnd_FileStream.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail::fnd { +class FileStream : Stream { +public: + enum AccessMode { + AccessMode_None, + AccessMode_Read, + AccessMode_Write, + AccessMode_ReadAndWrite, + AccessMode_AllowAppend, + AccessMode_AllowAppendAndWrite = 6, + }; + + virtual FndResult Open(const char* filePath, AccessMode openMode); + virtual void Flush(); + + virtual void EnableCache(void* buffer, size_t length); + virtual void DisableCache(); + virtual bool IsCacheEnabled() const; + + virtual s32 GetIoBufferAlignment() const; + + virtual bool CanSetFsAccessLog() const; + virtual void* SetFsAccessLog(FsAccessLog* pFsAccessLog); + + virtual position_t GetCachePosition(); + virtual size_t GetCachedLength(); + + ~FileStream() override; +}; +static_assert(sizeof(FileStream) == 0x8); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/io/atkfnd_FileStreamImpl.h b/include/nn/atk/fnd/io/atkfnd_FileStreamImpl.h new file mode 100644 index 0000000..a243f79 --- /dev/null +++ b/include/nn/atk/fnd/io/atkfnd_FileStreamImpl.h @@ -0,0 +1,83 @@ +#pragma once + +#include + +#include + +namespace nn::atk::detail::fnd { +class FileStreamImpl : FileStream { +public: + class DirectStream : fnd::Stream { + public: + ~DirectStream() override; + + void Close() override; + bool IsOpened() const override; + + size_t Read(void* buf, size_t length, FndResult* result) override; + size_t Write(const void* buf, size_t length, FndResult* result) override; + FndResult Seek(position_t offset, SeekOrigin origin) override; + + position_t GetCurrentPosition() const override; + size_t GetSize() const override; + + bool CanRead() const override; + bool CanWrite() const override; + bool CanSeek() const override; + + private: + FileStreamImpl* m_Owner; + }; + static_assert(sizeof(DirectStream) == 0x10); + + FileStreamImpl(); + ~FileStreamImpl() override; + + size_t Read(void* buf, size_t length, FndResult* result) override; + size_t Write(const void* buf, size_t length, FndResult* result) override; + FndResult Seek(position_t offset, fnd::Stream::SeekOrigin origin) override; + + bool CanRead() const override; + bool CanWrite() const override; + bool CanSeek() const override; + + void EnableCache(void* buffer, size_t length) override; + void DisableCache() override; + + void ValidateAlignment(void* buf); + + FndResult Open(const char* filePath, AccessMode accessMode) override; + void Close() override; + void Flush() override; + + bool IsOpened() const override; + + size_t GetSize() const override; + s32 GetIoBufferAlignment() const override; + + size_t ReadDirect(void* buf, size_t length, FndResult* result); + size_t WriteDirect(const void* buf, size_t length, FndResult* result); + FndResult SeekDirect(position_t offset, fnd::Stream::SeekOrigin origin); + + position_t GetCurrentPosition() const override; + + bool IsCacheEnabled() const override; + + bool CanSetFsAccessLog() const override; + void* SetFsAccessLog(FsAccessLog* pFsAccessLog) override; + + position_t GetCachePosition() override; + size_t GetCachedLength() override; + +private: + fs::FileHandle m_FileHandle; + bool m_IsOpened; + u8 m_Padding[3]; + size_t m_FileSize; + position_t m_CurrentPosition; + StreamCache m_StreamCache; + DirectStream m_DirectStream; + FsAccessLog* m_pAccessLog; +}; +static_assert(sizeof(FileStreamImpl) == 0x80); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/io/atkfnd_FileStreamProxy.h b/include/nn/atk/fnd/io/atkfnd_FileStreamProxy.h new file mode 100644 index 0000000..7987628 --- /dev/null +++ b/include/nn/atk/fnd/io/atkfnd_FileStreamProxy.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +class FileStreamProxy : FileStream { +public: + FileStreamProxy(const FileStream& fileStream, + position_t offset, size_t fileSize); + + ~FileStreamProxy() override; + + FndResult Open(const char* filePath, AccessMode openMode) override; + void Close() override; + void Flush() override; + + bool IsOpened() const override; + + bool CanRead() const override; + bool CanWrite() const override; + bool CanSeek() const override; + + size_t GetSize() const override; + + size_t Read(void* buffer, size_t length, FndResult* result) override; + size_t Write(const void* buffer, size_t length, FndResult* result) override; + FndResult Seek(position_t offset, fnd::Stream::SeekOrigin origin) override; + + position_t GetCurrentPosition() const override; + + void EnableCache(void* buffer, size_t length) override; + void DisableCache() override; + bool IsCacheEnabled() const override; + + s32 GetIoBufferAlignment() const override; + + bool CanSetFsAccessLog() const override; + + void* SetFsAccessLog(FsAccessLog* pFsAccessLog) override; + + position_t GetCachePosition() override; + + size_t GetCachedLength() override; + +private: + FileStream* m_pFileStream; + position_t m_Offset; + size_t m_FileSize; +}; +static_assert(sizeof(FileStreamProxy) == 0x20); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/io/atkfnd_Stream.h b/include/nn/atk/fnd/io/atkfnd_Stream.h new file mode 100644 index 0000000..552c2f9 --- /dev/null +++ b/include/nn/atk/fnd/io/atkfnd_Stream.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include + +namespace nn::atk::detail::fnd { +class Stream { +public: + enum SeekOrigin { + SeekOrigin_Begin, + SeekOrigin_End, + SeekOrigin_Current, + }; + + virtual ~Stream(); + + virtual void Close() = 0; + virtual bool IsOpened() const = 0; + + virtual size_t Read(void* buf, size_t length, FndResult* result) = 0; + virtual size_t Write(const void* buf, size_t length, FndResult* result) = 0; + virtual FndResult Seek(position_t offset, SeekOrigin origin) = 0; + + virtual position_t GetCurrentPosition() const = 0; + virtual size_t GetSize() const = 0; + + virtual bool CanRead() const = 0; + virtual bool CanWrite() const = 0; + virtual bool CanSeek() const = 0; +}; +static_assert(sizeof(Stream) == 0x8); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/io/atkfnd_StreamCache.h b/include/nn/atk/fnd/io/atkfnd_StreamCache.h new file mode 100644 index 0000000..9a4c61f --- /dev/null +++ b/include/nn/atk/fnd/io/atkfnd_StreamCache.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +struct FsAccessLog; + +class StreamCache { +public: + constexpr static position_t InvalidPosition = -1; + + StreamCache(); + StreamCache(Stream* sourceStream, void* buffer, size_t length); + + void Initialize(Stream* sourceStream, void* buffer, size_t length); + void Finalize(); + + size_t Read(void* buf, size_t length, FndResult* result, FsAccessLog* log, void* pFileStream); + + void FlushWriteCache(); + + size_t GetReadCacheHitLength(size_t) const; + + FndResult SyncStreamCurrentPosition(position_t position); + + void ClearCache(); + + size_t Write(const void* buf, size_t length, FndResult* result); + + size_t GetWritableCacheLength(size_t) const; + + FndResult Seek(position_t offset, Stream::SeekOrigin origin); + + virtual ~StreamCache(); + +private: + Stream* m_Stream{}; + position_t m_CurrentPosition{0}; + void* m_CacheBuffer{}; + size_t m_CacheBufferLength{0}; + position_t m_CachePosition{-1}; + size_t m_CachedLength{0}; + u8 m_CacheState{0}; + u8 m_Padding[3]; +}; +static_assert(sizeof(StreamCache) == 0x40); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/os/atkfnd_CriticalSection.h b/include/nn/atk/fnd/os/atkfnd_CriticalSection.h new file mode 100644 index 0000000..5f6a763 --- /dev/null +++ b/include/nn/atk/fnd/os/atkfnd_CriticalSection.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace nn::atk::detail::fnd { +class CriticalSection { +public: + void lock(); + bool tryLock(); + void unlock(); + +private: + os::Mutex m_Mutex; +}; +static_assert(sizeof(CriticalSection) == 0x20); +} // namespace nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/fnd/os/atkfnd_Thread.h b/include/nn/atk/fnd/os/atkfnd_Thread.h new file mode 100644 index 0000000..3c66da7 --- /dev/null +++ b/include/nn/atk/fnd/os/atkfnd_Thread.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include + +namespace nn::atk::detail::fnd { +class TimeSpan; + +class Thread { +public: + enum AffinityMask { + AffinityMask_CoreAll = -1, + AffinityMask_CoreDefault, + AffinityMask_Core0 = 1 << 0, + AffinityMask_Core1 = 1 << 1, + AffinityMask_Core2 = 1 << 2, + AffinityMask_Core3 = 1 << 3, + AffinityMask_Core4 = 1 << 4, + AffinityMask_Core5 = 1 << 5, + AffinityMask_Core6 = 1 << 6, + AffinityMask_Core7 = 1 << 7, + AffinityMask_Core8 = 1 << 8, + AffinityMask_Core9 = 1 << 9, + AffinityMask_Core10 = 1 << 10, + AffinityMask_Core11 = 1 << 11, + AffinityMask_Core12 = 1 << 12, + AffinityMask_Core13 = 1 << 13, + AffinityMask_Core14 = 1 << 14, + AffinityMask_Core15 = 1 << 15, + AffinityMask_Core16 = 1 << 16, + AffinityMask_Core17 = 1 << 17, + AffinityMask_Core18 = 1 << 18, + AffinityMask_Core19 = 1 << 19, + AffinityMask_Core20 = 1 << 20, + AffinityMask_Core21 = 1 << 21, + AffinityMask_Core22 = 1 << 22, + AffinityMask_Core23 = 1 << 23, + AffinityMask_Core24 = 1 << 24, + AffinityMask_Core25 = 1 << 25, + AffinityMask_Core26 = 1 << 26, + AffinityMask_Core27 = 1 << 27, + AffinityMask_Core28 = 1 << 28, + AffinityMask_Core29 = 1 << 29, + AffinityMask_Core30 = 1 << 30, + AffinityMask_Core31 = 1 << 31, + }; + + enum FsPriority { + FsPriority_RealTime, + FsPriority_Normal, + FsPriority_Low, + }; + + enum State { + State_NotRun, + State_Running, + State_Exited, + State_Released, + }; + + using Handle = os::ThreadType; + + constexpr static u64 InvalidId = 0xFFFFFFFF; + + constexpr static u32 DefaultThreadPriority = 16; + constexpr static u32 MinThreadPriority = 0; + constexpr static u32 MaxThreadPriority = 31; + + constexpr static u32 StackAlignment = 4096; + + class Handler { + public: + virtual ~Handler() = 0; + virtual u32 Run(void* param) = 0; + }; + static_assert(sizeof(Handler) == 0x8); + + struct RunArgs { + + RunArgs(); + + bool IsValid() const; + + char* name; + void* stack; + size_t stackSize; + s32 idealCoreNumber; + AffinityMask affinityMask; + s32 priority; + FsPriority fsPriority; + void* param; + Handler* handler; + }; + static_assert(sizeof(RunArgs) == 0x38); + + ~Thread(); + + bool Run(const RunArgs& args); + + void WaitForExit(); + + void Release(); + + void SetState(State state); + + s32 GetPriority() const; + State GetState() const; + + void OnRun(); + void OnExit(); + + Thread(); + + void SetPriority(s32 priority); + + static void Sleep(const TimeSpan& timeSpan); + + bool Create(const Handle& handle, s64& id, const RunArgs& args); + + void Detach(); + + void SetName(const char* name); + void SetAffinityMask(s32 idealCoreNumber, AffinityMask value); + + void Resume(); + void Join(); + + bool IsTerminated() const; + +private: + u32 m_State; + Handle m_Handle; + s64 m_Id; + s32 m_Priority; + FsPriority m_FsPriority; + void* m_Param; + Handler* m_Handler; + bool m_IsTerminated; +}; +static_assert(sizeof(Thread) == 0x1f0); +} // nn::atk::detail::fnd \ No newline at end of file diff --git a/include/nn/atk/submix/atk_ChannelMixVolume.h b/include/nn/atk/submix/atk_ChannelMixVolume.h new file mode 100644 index 0000000..17ad816 --- /dev/null +++ b/include/nn/atk/submix/atk_ChannelMixVolume.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace nn::atk { +class ChannelMixVolume { +public: + constexpr static u8 ChannelCountMax = 24; + + ChannelMixVolume(); + + void InitializeChannelVolume(); + + explicit ChannelMixVolume(const MixVolume& mixVolume); + ChannelMixVolume(const f32* channelVolumes, s32 channelCount); + + bool SetChannelCount(s32 channelCount); + + bool SetChannelVolume(s32 channel, f32 volume); + f32 GetChannelVolume(s32 channel) const; + + bool SetChannelVolume(s32 channel, const f32*, s32); + +private: + s32 m_ChannelCount; + f32 m_ChannelVolume[ChannelCountMax]; +}; +static_assert(sizeof(ChannelMixVolume) == 0x64); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/submix/atk_FinalMix.h b/include/nn/atk/submix/atk_FinalMix.h new file mode 100644 index 0000000..4de88fc --- /dev/null +++ b/include/nn/atk/submix/atk_FinalMix.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +#include + +namespace nn::atk { +class FinalMix : OutputMixer { +public: + static size_t GetRequiredMemorySize(bool isEffectEnabled); + + bool Initialize(audio::AudioRendererConfig* pConfig, s32 channelCount, + bool isEffectEnabled, void* buffer, size_t bufferSize); + + void Finalize(audio::AudioRendererConfig* pConfig); + + bool AppendEffect(EffectBase* pEffect, void* buffer, size_t bufferSize); + bool AppendEffect(EffectAux* pEffect, void* buffer, size_t bufferSize); + + bool RemoveEffect(EffectBase* pEffect); + bool RemoveEffect(EffectAux* pEffect); + + void ClearEffect(); + + bool IsEffectEnabled() const; + + ReceiverType GetReceiverType() const override; + s32 GetChannelCount() const override; + s32 GetBusCount() const override; + + void AddReferenceCount(s32 value) override; + + bool IsSoundSendClampEnabled(s32 bus) const override; + +private: + audio::FinalMixType m_FinalMix; + std::atomic_uint m_ReferenceCount; + s32 m_ChannelCount; +}; +static_assert(sizeof(FinalMix) == 0x50); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/submix/atk_OutputMixer.h b/include/nn/atk/submix/atk_OutputMixer.h new file mode 100644 index 0000000..c212856 --- /dev/null +++ b/include/nn/atk/submix/atk_OutputMixer.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace nn::atk { +class OutputMixer : protected OutputReceiver { +public: + using EffectList = util::IntrusiveList>; + using EffectAuxList = util::IntrusiveList>; + + OutputMixer(); + + static size_t GetRequiredMemorySize(s32 bus, bool isEffectEnabled); + + void Initialize(s32 bus, bool isEffectEnabled, void* buffer, size_t bufferSize); + void Finalize(); + + bool HasEffect(s32 bus) const; + + bool AppendEffect(EffectBase* pEffect, s32 bus, void* buffer, size_t bufferSize); + bool AppendEffect(EffectAux* pEffect, s32 bus, void* buffer, size_t bufferSize); + + bool RemoveEffect(EffectBase* pEffect, s32 bus); + bool RemoveEffect(EffectAux* pEffect, s32 bus); + + void ClearEffect(s32 bus); + + void UpdateEffectAux(); + + void OnChangeOutputMode(); + + virtual void AppendEffectImpl(EffectBase* pEffect, s32 bus, void* buffer, size_t bufferSize); + virtual void AppendEffectImpl(EffectAux* pEffect, s32 bus, void* buffer, size_t bufferSize); + + void RemoveEffectImpl(EffectBase* pEffect, s32 bus); + void RemoveEffectImpl(EffectAux* pEffect, s32 bus); + + void ClearEffectImpl(s32 bus); + +private: + detail::fnd::CriticalSection m_EffectListLock; + EffectList* m_pEffectList; + EffectAuxList* m_pEffectAuxList; + bool m_IsEffectEnabled; +}; +static_assert(sizeof(OutputMixer) == 0x40); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/submix/atk_OutputReceiver.h b/include/nn/atk/submix/atk_OutputReceiver.h new file mode 100644 index 0000000..1630a72 --- /dev/null +++ b/include/nn/atk/submix/atk_OutputReceiver.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace nn::atk { +class OutputReceiver { +public: + enum ReceiverType { + ReceiverType_SubMix, + ReceiverType_FinalMix, + }; + + virtual ReceiverType GetReceiverType() const = 0; + virtual s32 GetChannelCount() const = 0; + virtual s32 GetBusCount() const = 0; + virtual void AddReferenceCount(s32 value) = 0; + virtual bool IsSoundSendClampEnabled(s32 bus) const = 0; +}; +static_assert(sizeof(OutputReceiver) == 0x8); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/submix/atk_SubMix.h b/include/nn/atk/submix/atk_SubMix.h new file mode 100644 index 0000000..fd1ce9f --- /dev/null +++ b/include/nn/atk/submix/atk_SubMix.h @@ -0,0 +1,188 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nn::atk { +namespace detail::driver { +class HardwareManager; +}; + +class SubMix : OutputMixer { +public: + class SubMixParam { + public: + SubMixParam(); + + void SetSrcBusCount(s32 srcBusCount); + s32 GetSrcBusCount() const; + + void SetSrcChannelCount(s32 srcChannelCount); + s32 GetSrcChannelCount() const; + + void SetDstBusCount(s32 dstBusCount); + s32 GetDstBusCount() const; + + void SetDstChannelCount(s32 dstChannelCount); + s32 GetDstChannelCount() const; + + void SetOutputReceiver(const OutputReceiver* pOutputReceiver); + OutputReceiver* GetOutputReceiver() const; + + void SetEffectEnabled(bool isEffectEnabled); + bool IsEffectEnabled() const; + + void SetSoundSendClampEnabled(s32 index, bool IsSoundSendClampEnabled); + bool GetSoundSendClampEnabled(s32 index) const; + + private: + s32 m_SrcBusCount; + s32 m_SrcChannelCount; + s32 m_DstBusCount; + s32 m_DstChannelCount; + OutputReceiver* m_pOutputReceiver; + bool m_IsEffectEnabled; + bool m_IsSoundSendClampEnabledArray[24]; + }; + static_assert(sizeof(SubMixParam) == 0x38); + + class VolumeData { + public: + VolumeData(); + + bool Update(); + + private: + detail::MoveValue m_Volume; + bool m_IsMute; + bool m_IsPrevMute; + bool m_IsDirtyFlag; + }; + static_assert(sizeof(VolumeData) == 0x14); + + SubMix(); + + static size_t GetRequiredMemorySize(s32 srcBusCount, s32 srcChannelCount, + s32 dstBusCount, s32 dstChannelCount); + static size_t GetRequiredMemorySize(s32 srcBusCount, s32 srcChannelCount, + s32 dstBusCount, s32 dstChannelCount, + bool isEffectEnabled); + static size_t GetRequiredMemorySize(s32 srcBusCount, s32 srcChannelCount, + s32 dstBusCount, s32 dstChannelCount, + bool isEffectEnabled, bool isInternalCall); + + static size_t GetRequiredMemorySizeImpl(const SubMixParam& param); + + static size_t GetRequiredMemorySize(s32 srcBusCount, s32 dstBusCount, + const OutputReceiver* pReceiver, + bool isEffectEnabled); + + static size_t GetRequiredMemorySize(const SubMixParam& param); + + bool Initialize(s32 srcBusCount, s32 srcChannelCount, s32 dstBusCount, + s32 dstChannelCount, void* buffer, size_t bufferSize); + bool Initialize(s32 srcBusCount, s32 srcChannelCount, s32 dstBusCount, + s32 dstChannelCount, bool isEffectEnabled, void* buffer, + size_t bufferSize); + bool Initialize(s32 srcBusCount, s32 srcChannelCount, s32 dstBusCount, + s32 dstChannelCount, bool isEffectEnabled, bool isInternalCall, + void* buffer, size_t bufferSize); + + bool InitializeImpl(const SubMixParam& param, void* buffer, size_t bufferSize); + bool InitializeImpl(const SubMixParam& param, void* buffer, size_t bufferSize, bool isInternalCall); + + bool Initialize(s32 srcBusCount, s32 dstBusCount, const OutputReceiver* pReceiver, + void* buffer, size_t bufferSize); + bool Initialize(s32 srcBusCount, s32 dstBusCount, const OutputReceiver* pReceiver, + bool isEffectEnabled, void* buffer, size_t bufferSize); + bool Initialize(const SubMixParam& param, void* buffer, size_t bufferSize); + + void Finalize(); + + bool IsRemovable() const; + + void Update(); + + void UpdateBusMixVolume(s32 bus); + void UpdateChannelMixVolume(s32 bus); + void UpdateMixVolume(s32 srcBus, s32 srcChannel,s32 dstBus,s32 dstChannel); + + void SetDestination(OutputReceiver* pReceiver); + void ApplyDestination(); + + f32 GetSend(s32 srcBus, s32 dstBus) const; + f32 GetSendImpl(s32 srcBus, s32 srcChannel,s32 dstBus,s32 dstChannel) const; + + void SetSend(s32 srcBus, s32 dstBus, f32 send); + void SetSendImpl(s32 srcBus, s32 srcChannel,s32 dstBus,s32 dstChannel, f32 send); + + void SetBusVolume(s32 bus, f32 volume, s32 fadeFrame); + f32 GetBusVolume(s32 bus) const; + + void SetBusMute(s32 bus, bool isMute); + bool IsBusMuted(s32 bus) const; + + bool IsSoundSendClampEnabled(s32 bus) const override; + + void SetChannelVolume(s32 channel, f32 volume, s32 fadeFrame); + f32 GetChannelVolume(s32 channel) const; + + void SetChannelMute(s32 channel, bool isMute); + bool IsChannelMuted(s32 channel) const; + + void SetSubMixVolume(f32 volume, s32 fadeFrame); + f32 GetSubMixVolume() const; + + void SetSubMixMute(bool isMute); + bool IsSubMixMuted() const; + + void SetMuteUnusedEffectChannel(bool isUnusedEffectChannelMuted); + void IsUnusedEffectChannelMuted() const; + + void MuteUnusedEffectChannel(ChannelIndex* effectChannelIndex, s32 effectChannelCount, s32 bus); + + bool AppendEffect(EffectBase* pEffect, s32 bus, void* buffer, size_t bufferSize); + bool AppendEffect(EffectAux* pEffect, s32 bus, void* buffer, size_t bufferSize); + + bool RemoveEffect(EffectBase* pEffect, s32 bus); + bool RemoveEffect(EffectAux* pEffect, s32 bus); + + bool ClearEffect(s32 bus); + + bool IsEffectEnabled() const; + + void AppendEffectImpl(EffectBase* pEffect, s32 bus, void* buffer, size_t bufferSize) override; + void AppendEffectImpl(EffectAux* pEffect, s32 bus, void* buffer, size_t bufferSize) override; + + ReceiverType GetReceiverType() const override; + s32 GetChannelCount() const override; + s32 GetBusCount() const override; + + void AddReferenceCount(s32 value) override; + +private: + friend detail::driver::HardwareManager; + + util::IntrusiveListNode m_Link; + audio::SubMixType m_SubMix; + std::atomic_uint m_ReferenceCount; + OutputReceiver* m_pReceiver; + VolumeData* m_pBusVolume; + VolumeData* m_pChannelVolume; + VolumeData m_SubMixVolume; + bool* m_pIsSoundSendClampEnabledArray; + f32** m_ppSendVolume; + s32 m_ChannelCount; + s32 m_BusCount; + s32 m_ReceiverChannelCountMax; + detail::fnd::CriticalSection m_VolumeLock; + detail::fnd::CriticalSection m_DestinationLock; + bool m_IsInitialized; + bool m_IsUnusedEffectChannelMuted; + bool m_IsAppliedOutputReceiver; +}; +static_assert(sizeof(SubMix) == 0xf8); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/util/atk_AudioRendererPerformanceReader.h b/include/nn/atk/util/atk_AudioRendererPerformanceReader.h new file mode 100644 index 0000000..9f58ecc --- /dev/null +++ b/include/nn/atk/util/atk_AudioRendererPerformanceReader.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include + +namespace nn::atk { +class AudioRendererPerformanceReader { +public: + constexpr static u32 PerformanceInfoCountMin = 2; + + struct PerformanceInfo { + void* performanceBuffer; + size_t performanceBufferSize; + os::Tick tick; + }; + + AudioRendererPerformanceReader(); + + static size_t GetRequiredMemorySize(s32); + + void Initialize(s32, void*, size_t); + PerformanceInfo* ReadPerformanceInfo(); + + void Record(const void* performanceFrameBuffer, size_t performanceFrameBufferSize, os::Tick tick); + +private: + PerformanceInfo* m_pPerformanceInfo{}; + s32 m_PerformanceInfoCount{0}; + std::atomic_int m_WriteIndex{0}; + std::atomic_int m_ReadIndex{0}; + bool m_IsInitialized{false}; +}; +static_assert(sizeof(AudioRendererPerformanceReader) == 0x18); + +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/util/atk_DeviceOutRecorder.h b/include/nn/atk/util/atk_DeviceOutRecorder.h new file mode 100644 index 0000000..47cc76a --- /dev/null +++ b/include/nn/atk/util/atk_DeviceOutRecorder.h @@ -0,0 +1,148 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +namespace nn::atk { +class DeviceOutRecorder : detail::fnd::Thread::Handler { +public: + enum State { + State_NotInitialized, + State_Initialized, + State_Recording, + State_Recorded, + }; + + enum Message { + Message_Prepare, + Message_WriteSamples, + Message_RequestStop, + Message_Exit, + }; + + constexpr static u32 RecordingBufferSize = 0x5a000; + constexpr static u32 DefaultWriteBlockPerSamples = 0x10000; + constexpr static u32 RequiredThreadStackSize = 0x10000; + + struct RecordingOptions { + u32 m_Channels; + bool m_IsLeadSilenceTrimmingEnabled; + u32 m_MaxFrames; + u32 m_WriteBlockPerSamples; + }; + static_assert(sizeof(RecordingOptions) == 0x10); + + struct InitializationOptions { + u32 m_Priority; + s32 m_IdealCoreNumber; + }; + static_assert(sizeof(InitializationOptions) == 0x8); + + class RecorderBuffer { + struct WriteState { + u32 channelIndex; + u32 writtenSampleCount; + }; + static_assert(sizeof(WriteState) == 0x8); + + explicit RecorderBuffer(const char* deviceName); + + void Initialize(s16* sampleBuffer, u32 maxSamples); + + void UpdateMaxSamples(); + + void Clear(); + + void Finalize(); + + u32 Push(const s16* sampleBuffer, u32 samples); + u32 Pop(u32); + s64 Peek(); + + void SetReadBlockSamples(u32 readBlockSamples); + + private: + s16* m_SampleBuffer; + u32 m_MaxBufferSamples; + u32 m_MaxSamples; + std::atomic_uint m_ValidSamples; + u32 m_ReadPosition; + u32 m_WritePosition; + u32 m_ReadBlockSamples; + WriteState m_WriteState; + char* m_DeviceName; + }; + static_assert(sizeof(RecorderBuffer) == 0x30); + + explicit DeviceOutRecorder(const char* deviceName); + ~DeviceOutRecorder() override; + + void Finalize(); + + bool Initialize(void*, size_t, void*, size_t); + bool Initialize(void*, size_t, void*, size_t, const InitializationOptions& options); + + bool StartThread(u32, s32); + + static size_t GetRequiredMemorySizeForRecording(); + + void Stop(bool); + void StopThread(); + + bool Start(detail::fnd::FileStream&, const RecordingOptions& options); + + s32 GetReadBlockSamples(u32) const; + + s32 Prepare(); + + bool SendMessage(Message message); + + void RecordSamples(const s16* sampleBuffer, u32 samples); + + bool PostMessage(Message message); + + u32 Run(void* param) override; + + s32 OnPrepare(); + bool OnWriteSamples(bool); + void OnRequestStop(); + void OnExit(); + + u64 GetLeadSilenceSamples(const s16* sampleBuffer, u32 sampleCount, u32) const; + u32 GetWritableSamples(u32) const; + + bool IsNoMoreSamples() const; + + void OnStart(); + void OnStop(); + + u32 OnProcessSamples(s16* sampleBuffer, u32 samples); + +private: + State m_State; + u32 m_Channels; + OutputMode m_OutputMode; + bool m_IsLeadSilenceTrimming; + u32 m_MaxSamples; + u32 m_WrittenSamples; + detail::fnd::Thread m_Thread; + void* m_ThreadStack; + os::MessageQueue m_MessageQueue; + std::uintptr_t m_Message; + s32 m_MessageResult; + os::Event m_MessageDoneEvent; + detail::fnd::FileStream* m_Stream; + detail::WavOutFileStream m_WavOutStream; + RecorderBuffer m_RecordingBuffer; + util::BytePtr m_WorkBuffer; + u32 m_WriteBlockPerSamples; +}; +static_assert(sizeof(DeviceOutRecorder) == 0x310); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/util/atk_ProfileReader.h b/include/nn/atk/util/atk_ProfileReader.h new file mode 100644 index 0000000..853e6f4 --- /dev/null +++ b/include/nn/atk/util/atk_ProfileReader.h @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include +#include +#include + +namespace nn::atk { +struct TimeRange { + os::Tick begin; + os::Tick end; +}; +static_assert(sizeof(TimeRange) == 0x10); + +struct SoundProfile { + TimeRange nwFrameProcess; + TimeRange mainMixProcess; + TimeRange finalMixProcess; + TimeRange voiceProcess; + TimeRange sinkProcess; + TimeRange circularBufferSinkProcess; + TimeRange rendererFrameProcess; + u32 totalVoiceCount; + u32 rendererVoiceCount; + u32 nwVoiceCount; + u64 nwFrameProcessTick; + TimeRange _additionalSubMixProcess; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + TimeRange _voiceProcessTable[96]; + audio::NodeId _voiceIdTable[96]; +#else + TimeRange _voiceProcessTable[192]; + audio::NodeId _voiceIdTable[192]; +#endif +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(SoundProfile) == 0x818); +#else +static_assert(sizeof(SoundProfile) == 0xf98); +#endif + +struct SoundThreadUpdateProfile { + TimeRange soundThreadProcess; + TimeRange _updateLowLevelVoiceProcess; + TimeRange _updateRendererProcess; + TimeRange _waitRendererEventProcess; + TimeRange _userEffectFrameProcess; + TimeRange _frameProcess; +}; +static_assert(sizeof(SoundThreadUpdateProfile) == 0x60); + +class ProfileReader { +public: + ProfileReader(); + + size_t Read(SoundProfile*, s32); + + void Record(const SoundProfile& src); + + util::IntrusiveListNode m_Link; + +private: + SoundProfile m_ProfileBuffer[32]; + s32 m_ProfileBufferRead; + s32 m_ProfileBufferWrite; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(ProfileReader) == 0x10318); +#else +static_assert(sizeof(ProfileReader) == 0x1f318); +#endif + +using ProfileReaderList = util::IntrusiveList>; + +struct TaskProfile; + +template +class AtkProfileReader { +public: + util::IntrusiveListNode m_List; + +private: + bool m_IsInitialized; + TaskProfile* m_pProfile; + s32 m_ProfileCount; + s32 m_RecordIndex; + s32 m_ReadIndex; + std::atomic_int m_ReadableCount; +}; + +using SoundThreadUpdateProfileReader = AtkProfileReader; +using SoundThreadUpdateProfileReaderList = util::IntrusiveList>; +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/atk/util/atk_TaskProfileReader.h b/include/nn/atk/util/atk_TaskProfileReader.h new file mode 100644 index 0000000..0e7e680 --- /dev/null +++ b/include/nn/atk/util/atk_TaskProfileReader.h @@ -0,0 +1,146 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace nn::atk { + +namespace detail::driver { +class StreamSoundPlayer; +} // namespace nn::atk::detail::driver + +struct TaskProfile { + enum TaskProfileType { + TaskProfileType_LoadStreamBlock, + TaskProfileType_LoadOpusStreamBlock, + }; + + class LoadStreamBlock { + public: + TimeSpan GetTotalTime() const; + u64 GetBeginTick() const; + u64 GetEndTick() const; + + f32 GetRemainingCachePercentage() const; + size_t GetCachedLength() const; + +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + detail::driver::StreamSoundPlayer* GetStreamSoundPlayer() const; +#endif + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void SetTick(const os::Tick& beginTick, const os::Tick& endTick); +#else + void SetData(const os::Tick& beginTick, const os::Tick& endTick, + const detail::IStreamDataDecoder::CacheProfile& cacheProfile); +#endif + + private: + u64 m_BeginTick; + u64 m_EndTick; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + position_t m_CacheStartPosition; + size_t m_CachedLength; + position_t m_CacheCurrentPosition; + detail::driver::StreamSoundPlayer* m_pPlayer; +#endif + }; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + static_assert(sizeof(LoadStreamBlock) == 0x10); +#else + static_assert(sizeof(LoadStreamBlock) == 0x30); +#endif + + class LoadOpusStreamBlock { + public: + TimeSpan GetTotalTime() const; + u64 GetBeginTick() const; + u64 GetEndTick() const; + + f32 GetRemainingCachePercentage() const; + size_t GetCachedLength() const; + + TimeSpan GetDecodeTime() const; + s32 GetDecodedSampleCount() const; + + TimeSpan GetFsAccessTime(); + size_t GetFsReadSize(); + +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + detail::driver::StreamSoundPlayer* GetStreamSoundPlayer() const; +#endif + +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + void SetData(const os::Tick& beginTick, const os::Tick& endTick, + detail::IStreamDataDecoder::DecodeProfile* decodeProfile); +#else + void SetData(const os::Tick& beginTick, const os::Tick& endTick, + const detail::IStreamDataDecoder::DecodeProfile& decodeProfile, + const detail::IStreamDataDecoder::CacheProfile& cacheProfile); +#endif + + private: + u64 m_BeginTick; + u64 m_EndTick; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + position_t m_CacheStartPosition; + size_t m_CachedLength; + position_t m_CacheCurrentPosition; +#endif + u64 m_DecodeTick; + u64 m_FsAccessTick; + size_t m_FsReadSize; + s32 m_DecodedSampleCount; +#if NN_SDK_VER >= NN_MAKE_VER(4, 0, 0) + detail::driver::StreamSoundPlayer* m_pPlayer; +#endif + }; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) + static_assert(sizeof(LoadOpusStreamBlock) == 0x30); +#else + static_assert(sizeof(LoadOpusStreamBlock) == 0x50); +#endif + + TaskProfileType type; + union { + LoadStreamBlock loadStreamBlock; + LoadOpusStreamBlock loadOpusStreamBlock; + }; +}; +#if NN_SDK_VER < NN_MAKE_VER(4, 0, 0) +static_assert(sizeof(TaskProfile) == 0x38); +#else +static_assert(sizeof(TaskProfile) == 0x58); +#endif + +using TaskProfileReader = AtkProfileReader; + +class TaskProfileLogger { +public: + using TaskProfileReaderList = util::IntrusiveList>; + + TaskProfileLogger(); + + void Record(const TaskProfile& profile); + + void RegisterReader(TaskProfileReader& profileReader); + void UnregisterReader(const TaskProfileReader& profileReader); + + void SetProfilingEnabled(bool isEnabledProfiling); + + void Finalize(); + +private: + TaskProfileReaderList m_List; + detail::fnd::CriticalSection m_Lock; + bool m_IsProfilingEnabled; +}; +static_assert(sizeof(TaskProfileLogger) == 0x38); +} // namespace nn::atk \ No newline at end of file diff --git a/include/nn/audio.h b/include/nn/audio.h index bd8c86e..ba11522 100644 --- a/include/nn/audio.h +++ b/include/nn/audio.h @@ -6,150 +6,29 @@ #pragma once #include -#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace nn { namespace audio { // Common audio -struct AudioDeviceName { - char raw_name[0x100]; -}; - -static_assert(sizeof(AudioDeviceName) == 0x100); - void AcquireAudioDeviceSwitchNotification(nn::os::SystemEvent* event); s32 ListAudioDeviceName(nn::audio::AudioDeviceName* buffer, s32 bufferCount); Result SetAudioDeviceOutputVolume(nn::audio::AudioDeviceName const* device, float volume); u32 GetActiveChannelCount(); -struct AudioRendererConfig { - u64* _0; - u64* _8; - u64* _10; - u64* _18; - u64* _20; - u64* _28; - u64* _30; - u64* _38; - u64* _40; - u64* _48; - u64* _50; -}; - -enum AudioRendererRenderingDevice : u32 { - AudioRendererRenderingDevice_Cpu, - AudioRendererRenderingDevice_Dsp -}; - -enum AudioRendererExecutionMode : u32 { - AudioRendererExecutionMode_Manual, - AudioRendererExecutionMode_Auto, -}; - -enum SampleFormat : u32 { - SampleFormat_Invalid, - SampleFormat_PcmInt8, - SampleFormat_PcmInt16, - SampleFormat_PcmInt24, - SampleFormat_PcmInt32, - SampleFormat_PcmFloat, - SampleFormat_Adpcm, -}; - -enum MemoryPoolState : u32 { - MemoryPoolState_Invalid, - MemoryPoolState_New, - MemoryPoolState_RequestDetach, - MemoryPoolState_Detached, - MemoryPoolState_RequestAttach, - MemoryPoolState_Attached, - MemoryPoolState_Released, -}; - -struct AudioRendererParameter { - u32 sampleRate; - u32 sampleCount; - u32 mixBufferCount; - u32 subMixCount; - u32 voiceCount; - u32 sinkCount; - u32 effectCount; - u32 performanceFrameCount; - bool isVoiceDropEnabled; - u32 splitterCount; - u32 splitterSendChannelCount; - AudioRendererRenderingDevice renderingDevice; - AudioRendererExecutionMode executionMode; - u32 _34; - u32 revision; -}; - -static_assert(sizeof(AudioRendererParameter) == 0x3C); - -struct BiquadFilterParameter { - bool enabled; - s16 numerator[3]; - s16 denominator[2]; -}; - -static_assert(sizeof(BiquadFilterParameter) == 0xC); - -struct WaveBuffer { - void* buffer; - size_t bufferSize; - s32 startSampleOffset; - s32 endSampleOffset; - bool shouldLoop; - bool isEndOfStream; - void* context; - size_t contextSize; -}; - -static_assert(sizeof(WaveBuffer) == 0x30); - -struct AudioRendererHandle { - u64* _0; - u64* _8; -}; - -struct MemoryPoolType { - u64* _0; -}; - -struct CircularBufferSinkType { - u64* _0; -}; - -struct AuxType { - u64* _0; -}; - -struct DelayType { - u64* _0; -}; - -struct FinalMixType { - u64* _0; -}; - -struct SubMixType { - u64* _0; -}; - -struct VoiceType { - u64* _0; - - enum PlayState : u32 { - PlayState_Start, - PlayState_Stop, - PlayState_Pause, - }; -}; - -struct DeviceSinkType { - u64* _0; -}; - // Audio Renderer base APIs void InitializeAudioRendererParameter(nn::audio::AudioRendererParameter* inParameter); bool IsValidAudioRendererParameter(nn::audio::AudioRendererParameter const& inParameter); @@ -211,68 +90,6 @@ GetRequiredBufferSizeForPerformanceFrames(nn::audio::AudioRendererParameter cons void* SetPerformanceFrameBuffer(nn::audio::AudioRendererConfig* config, void* buffer, size_t bufferSize); -enum PerformanceEntryType : u8 { - PerformanceEntryType_Invalid, - PerformanceEntryType_Voice, - PerformanceEntryType_SubMix, - PerformanceEntryType_FinalMix, - PerformanceEntryType_Sink -}; - -struct PerformanceEntry { - s32 nodeId; - s32 startTime; - s32 processingTime; - PerformanceEntryType entryType; -}; - -static_assert(sizeof(PerformanceEntry) == 0x10); - -enum PerformanceDetailType : u8 { - PerformanceDetailType_Unknown, - PerformanceDetailType_PcmInt16, - PerformanceDetailType_Adpcm, - PerformanceDetailType_VolumeRamp, - PerformanceDetailType_BiquadFilter, - PerformanceDetailType_Mix, - PerformanceDetailType_Delay, - PerformanceDetailType_Aux, - PerformanceDetailType_Reverb, - PerformanceDetailType_Reverb3d, - PerformanceDetailType_PcmFloat -}; - -struct PerformanceDetail { - s32 nodeId; - s32 startTime; - s32 processingTime; - PerformanceDetailType detailType; - PerformanceEntryType entryType; -}; - -static_assert(sizeof(PerformanceDetail) == 0x10); - -class PerformanceInfo { -public: - PerformanceInfo(); - ~PerformanceInfo(); - - bool SetBuffer(void const* buffer, size_t bufferSize); - bool MoveToNextFrame(); - s32 GetTotalProcessingTime(); - PerformanceEntry GetEntries(s32* count); - PerformanceDetail GetDetails(s32* count); - -private: - void* buffer; - size_t bufferSize; - void* header; - PerformanceEntry* entries; - PerformanceDetail* details; -}; - -static_assert(sizeof(PerformanceInfo) == 0x28); - // Audio Renderer Sink APIs Result AddDeviceSink(nn::audio::AudioRendererConfig* config, nn::audio::DeviceSinkType* sink, nn::audio::FinalMixType* mix, s8 const* input, s32 inputCount, diff --git a/include/nn/audio/audio_Adpcm.h b/include/nn/audio/audio_Adpcm.h new file mode 100644 index 0000000..123e8ab --- /dev/null +++ b/include/nn/audio/audio_Adpcm.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace nn::audio { +struct AdpcmContext { + u16 predScale; + s16 history[2]; +}; +static_assert(sizeof(AdpcmContext) == 0x6); + +struct AdpcmParameter { + u16 coefficients[16]; +}; +static_assert(sizeof(AdpcmParameter) == 0x20); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_AudioRendererTypes.h b/include/nn/audio/audio_AudioRendererTypes.h new file mode 100644 index 0000000..099a425 --- /dev/null +++ b/include/nn/audio/audio_AudioRendererTypes.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +namespace nn::audio { +enum AudioRendererRenderingDevice { + AudioRendererRenderingDevice_AudioCoprocessor, + AudioRendererRenderingDevice_Cpu, +}; + +enum AudioRendererExecutionMode { + AudioRendererExecutionMode_AutoExecution, + AudioRendererExecutionMode_ManualExecution, +}; + +struct AudioRendererParameter { + s32 sampleRate; + s32 sampleCount; + s32 mixBufferCount; + s32 subMixCount; + s32 voiceCount; + s32 sinkCount; + s32 effectCount; + s32 performanceFrameCount; + bool isVoiceDropEnabled; + s32 splitterCount; + s32 splitterSendChannelCount; + AudioRendererRenderingDevice renderingDevice; + AudioRendererExecutionMode executionMode; + u32 _magic; +}; +static_assert(sizeof(AudioRendererParameter) == 0x38); + +struct AudioRendererConfig { + VoiceInfoManager* _pVoiceInfoManager; + MixManager* _pMixManager; + EffectManager* _pEffectManager; + SinkManager* _pSinkManager; + PerformanceBufferManager* _pPerformanceBufferManager; + MemoryPoolManager* _pMemoryPoolManager; + BehaviorManager* _pBehaviorManager; + SplitterInfoManager* _pSplitterInfoManager; + void* _pInParameter; + size_t _pInParameterSize; + void* _pOutStatus; + size_t _pOutStatusSize; + void* _pConfigBuffer; + size_t _configBufferSize; +}; +static_assert(sizeof(AudioRendererConfig) == 0x70); + +struct AudioRendererHandle { + void* _handle; + void* _context; +}; +static_assert(sizeof(AudioRendererHandle) == 0x10); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_Common.h b/include/nn/audio/audio_Common.h new file mode 100644 index 0000000..7cc0ed3 --- /dev/null +++ b/include/nn/audio/audio_Common.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace nn::audio { +using NodeId = uint32_t; + +struct AudioDeviceName { + char raw_name[0x100]; +}; +static_assert(sizeof(AudioDeviceName) == 0x100); + +struct DelayType { + u64* _0; +}; + +struct EffectInfo {}; +struct MixInfo {}; + +class VoiceInfoManager {}; +class MixManager {}; +class EffectManager {}; +class SinkManager {}; +class PerformanceBufferManager {}; +class MemoryPoolManager {}; +class BehaviorManager {}; +class SplitterInfoManager {}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_EffectTypes.h b/include/nn/audio/audio_EffectTypes.h new file mode 100644 index 0000000..31d0c14 --- /dev/null +++ b/include/nn/audio/audio_EffectTypes.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace nn::audio { +struct AuxType { + EffectInfo* _pEffectInfo; +}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_FinalMixTypes.h b/include/nn/audio/audio_FinalMixTypes.h new file mode 100644 index 0000000..08434be --- /dev/null +++ b/include/nn/audio/audio_FinalMixTypes.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace nn::audio { +struct FinalMixType { + MixInfo* _pMixInfo; +}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_MemoryPoolTypes.h b/include/nn/audio/audio_MemoryPoolTypes.h new file mode 100644 index 0000000..7c97602 --- /dev/null +++ b/include/nn/audio/audio_MemoryPoolTypes.h @@ -0,0 +1,27 @@ +#pragma once + +namespace nn::audio { +enum MemoryPoolState { + MemoryPoolState_Invalid, + MemoryPoolState_New, + MemoryPoolState_RequestDetach, + MemoryPoolState_Detached, + MemoryPoolState_RequestAttach, + MemoryPoolState_Attached, + MemoryPoolState_Released, +}; + +struct MemoryPoolInfo {}; + +struct MemoryPoolType { + enum State { + State_RequestAttach, + State_Attached, + State_RequestDetach, + State_Detached, + }; + + MemoryPoolInfo* _pMemoryPoolInfo; +}; +static_assert(sizeof(MemoryPoolType) == 0x8); +} // namespace nn::audio diff --git a/include/nn/audio/audio_PerformanceMetrics.h b/include/nn/audio/audio_PerformanceMetrics.h new file mode 100644 index 0000000..05053d6 --- /dev/null +++ b/include/nn/audio/audio_PerformanceMetrics.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace nn::audio { +class PerformanceInfo { +public: + PerformanceInfo(); + ~PerformanceInfo(); + + void SetBuffer(const void* buffer, size_t bufferSize); + void MoveToNextFrame(); + + PerformanceEntry* GetEntries(s32*); + void GetTotalProcessingTime(); + +private: + void* m_Buffer; + size_t m_BufferSize; + PerformanceFrameHeader* m_Header; + PerformanceEntry* m_Entries; + PerformanceDetail* m_Details; +}; +static_assert(sizeof(PerformanceInfo) == 0x28); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_PerformanceMetricsTypes.h b/include/nn/audio/audio_PerformanceMetricsTypes.h new file mode 100644 index 0000000..483a91f --- /dev/null +++ b/include/nn/audio/audio_PerformanceMetricsTypes.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace nn::audio { +enum PerformanceEntryType { + PerformanceEntryType_Unknown, + PerformanceEntryType_Voice, + PerformanceEntryType_SubMix, + PerformanceEntryType_FinalMix, + PerformanceEntryType_Sink, + PerformanceEntryType_Count +}; + +enum PerformanceDetailType : u8 { + PerformanceDetailType_Unknown, + PerformanceDetailType_PcmInt16, + PerformanceDetailType_Adpcm, + PerformanceDetailType_VolumeRamp, + PerformanceDetailType_BiquadFilter, + PerformanceDetailType_Mix, + PerformanceDetailType_Delay, + PerformanceDetailType_Aux, + PerformanceDetailType_Reverb, + PerformanceDetailType_Reverb3d, + PerformanceDetailType_PcmFloat +}; + +struct PerformanceEntry { + NodeId id; + s32 startTime; + s32 processingTime; + s8 entryType; + s8 _padding[3]; +}; +static_assert(sizeof(PerformanceEntry) == 0x10); + +struct PerformanceFrameHeader {}; +struct PerformanceDetail {}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_SampleFormat.h b/include/nn/audio/audio_SampleFormat.h new file mode 100644 index 0000000..4380b22 --- /dev/null +++ b/include/nn/audio/audio_SampleFormat.h @@ -0,0 +1,13 @@ +#pragma once + +namespace nn::audio { +enum SampleFormat { + SampleFormat_Invalid, + SampleFormat_PcmInt8, + SampleFormat_PcmInt16, + SampleFormat_PcmInt24, + SampleFormat_PcmInt32, + SampleFormat_PcmFloat, + SampleFormat_Adpcm, +}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_SinkTypes.h b/include/nn/audio/audio_SinkTypes.h new file mode 100644 index 0000000..d9775ff --- /dev/null +++ b/include/nn/audio/audio_SinkTypes.h @@ -0,0 +1,20 @@ +#pragma once + +namespace nn::audio { +struct SinkInfo {}; + +struct DeviceSinkType { + struct DownMixParameter { + float coeff[16]; + }; + static_assert(sizeof(DownMixParameter) == 0x40); + + SinkInfo* _handle; +}; +static_assert(sizeof(DeviceSinkType) == 0x8); + +struct CircularBufferSinkType { + SinkInfo* _handle; +}; +static_assert(sizeof(CircularBufferSinkType) == 0x8); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_SubMixTypes.h b/include/nn/audio/audio_SubMixTypes.h new file mode 100644 index 0000000..69faf8e --- /dev/null +++ b/include/nn/audio/audio_SubMixTypes.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace nn::audio { +struct SubMixType { + MixInfo* _pMixInfo; +}; +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_VoiceTypes.h b/include/nn/audio/audio_VoiceTypes.h new file mode 100644 index 0000000..e533772 --- /dev/null +++ b/include/nn/audio/audio_VoiceTypes.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace nn::audio { +struct VoiceInfo; + +struct VoiceType { + enum PlayState { + PlayState_Play, + PlayState_Stop, + PlayState_Pause, + }; + + VoiceInfo* _pVoiceInfo; +}; +static_assert(sizeof(VoiceType) == 0x8); + +struct BiquadFilterParameter { + bool enable; + s16 numerator[3]; + s16 denominator[2]; +}; +static_assert(sizeof(BiquadFilterParameter) == 0xc); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/audio/audio_WaveBuffer.h b/include/nn/audio/audio_WaveBuffer.h new file mode 100644 index 0000000..282ae5d --- /dev/null +++ b/include/nn/audio/audio_WaveBuffer.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace nn::audio { +struct WaveBuffer { + void* buffer; + size_t size; + s32 startSampleOffset; + s32 endSampleOffset; + bool loop; + bool isEndOfStream; + void* pContext; + size_t contextSize; +}; +static_assert(sizeof(WaveBuffer) == 0x30); +} // namespace nn::audio \ No newline at end of file diff --git a/include/nn/os/os_MessageQueue.h b/include/nn/os/os_MessageQueue.h new file mode 100644 index 0000000..22084b1 --- /dev/null +++ b/include/nn/os/os_MessageQueue.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace nn::os { +class MessageQueue { +public: + MessageQueueType m_MessageQueue; +}; +} // namespace nn::os \ No newline at end of file diff --git a/include/nn/util/util_IntrusiveList.h b/include/nn/util/util_IntrusiveList.h index a0d7b42..47eab31 100644 --- a/include/nn/util/util_IntrusiveList.h +++ b/include/nn/util/util_IntrusiveList.h @@ -330,6 +330,15 @@ class IntrusiveList { detail::IntrusiveListImplementation m_Implementation; }; +template +class IntrusiveListBaseNode : IntrusiveListNode {}; + +template +class IntrusiveListBaseNodeTraits { +public: + using BaseNodeType = IntrusiveListBaseNode; +}; + template class IntrusiveListMemberNodeTraits { friend class IntrusiveList;