// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include "audio_core/renderer/splitter/splitter_destinations_data.h"
#include "audio_core/renderer/splitter/splitter_info.h"
#include "common/common_types.h"
namespace AudioCore {
struct AudioRendererParameterInternal;
class WorkbufferAllocator;
namespace Renderer {
class BehaviorInfo;
/**
* The splitter allows much more control over how sound is mixed together.
* Previously, one mix can only connect to one other, and you may need
* more mixes (and duplicate processing) to achieve the same result.
* With the splitter, many-to-one and one-to-many mixing is possible.
* This was added in revision 2.
* Had a bug with incorrect numbers of destinations, fixed in revision 5.
*/
class SplitterContext {
struct InParameterHeader {
/* 0x00 */ u32 magic; // 'SNDH'
/* 0x04 */ s32 info_count;
/* 0x08 */ s32 destination_count;
/* 0x0C */ char unk0C[0x14];
};
static_assert(sizeof(InParameterHeader) == 0x20,
"SplitterContext::InParameterHeader has the wrong size!");
public:
/**
* Get a destination mix from the given splitter and destination index.
*
* @param splitter_id - Splitter index to get from.
* @param destination_id - Destination index within the splitter.
* @return Pointer to the found destination. May be nullptr.
*/
SplitterDestinationData* GetDestinationData(s32 splitter_id, s32 destination_id);
/**
* Get a splitter from the given index.
*
* @param index - Index of the desired splitter.
* @return Splitter requested.
*/
SplitterInfo& GetInfo(s32 index);
/**
* Get the total number of splitter destinations.
*
* @return Number of destinations.
*/
u32 GetDataCount() const;
/**
* Get the total number of splitters.
*
* @return Number of splitters.
*/
u32 GetInfoCount() const;
/**
* Get a specific global destination.
*
* @param index - Index of the desired destination.
* @return The requested destination.
*/
SplitterDestinationData& GetData(u32 index);
/**
* Check if the splitter is in use.
*
* @return True if any splitter or destination is in use, otherwise false.
*/
bool UsingSplitter() const;
/**
* Mark all splitters as having new connections.
*/
void ClearAllNewConnectionFlag();
/**
* Initialize the context.
*
* @param behavior - Used to check for splitter support.
* @param params - Input parameters.
* @param allocator - Allocator used to allocate workbuffer memory.
*/
bool Initialize(const BehaviorInfo& behavior, const AudioRendererParameterInternal& params,
WorkbufferAllocator& allocator);
/**
* Update the context.
*
* @param input - Input buffer with the new info,
* expected to point to a InParameterHeader.
* @param consumed_size - Output with the number of bytes consumed from input.
*/
bool Update(const u8* input, u32& consumed_size);
/**
* Update the splitters.
*
* @param input - Input buffer with the new info.
* @param offset - Current offset within the input buffer,
* input + offset should point to a SplitterInfo::InParameter.
* @param splitter_count - Number of splitters in the input buffer.
* @return Number of bytes consumed in input.
*/
u32 UpdateInfo(const u8* input, u32 offset, u32 splitter_count);
/**
* Update the splitters.
*
* @param input - Input buffer with the new info.
* @param offset - Current offset within the input buffer,
* input + offset should point to a
* SplitterDestinationData::InParameter.
* @param destination_count - Number of destinations in the input buffer.
* @return Number of bytes consumed in input.
*/
u32 UpdateData(const u8* input, u32 offset, u32 destination_count);
/**
* Update the state of all destinations in all splitters.
*/
void UpdateInternalState();
/**
* Replace the given splitter's destinations with new ones.
*
* @param out_info - Splitter to recompose.
* @param info_header - Input parameters containing new destination ids.
*/
void RecomposeDestination(SplitterInfo& out_info, const SplitterInfo::InParameter* info_header);
/**
* Old calculation for destinations, this is the thing the splitter bug fixes.
* Left for compatibility, and now min'd with the actual count to not bug.
*
* @return Number of splitter destinations.
*/
u32 GetDestCountPerInfoForCompat() const;
/**
* Calculate the size of the required workbuffer for splitters and destinations.
*
* @param behavior - Used to check splitter features.
* @param params - Input parameters with splitter/destination counts.
* @return Required buffer size.
*/
static u64 CalcWorkBufferSize(const BehaviorInfo& behavior,
const AudioRendererParameterInternal& params);
private:
/**
* Setup the context.
*
* @param splitter_infos - Workbuffer for splitters.
* @param splitter_info_count - Number of splitters in the workbuffer.
* @param splitter_destinations - Workbuffer for splitter destinations.
* @param destination_count - Number of destinations in the workbuffer.
* @param splitter_bug_fixed - Is the splitter bug fixed?
*/
void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count,
SplitterDestinationData* splitter_destinations, u32 destination_count,
bool splitter_bug_fixed);
/// Workbuffer for splitters
std::span<SplitterInfo> splitter_infos{};
/// Number of splitters in buffer
s32 info_count{};
/// Workbuffer for destinations
SplitterDestinationData* splitter_destinations{};
/// Number of destinations in buffer
s32 destinations_count{};
/// Is the splitter bug fixed?
bool splitter_bug_fixed{};
};
} // namespace Renderer
} // namespace AudioCore