2020-07-12 12:59:14 +01:00
|
|
|
// Copyright 2020 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stack>
|
|
|
|
#include <vector>
|
|
|
|
#include "audio_core/common.h"
|
|
|
|
#include "common/common_funcs.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/swap.h"
|
|
|
|
|
|
|
|
namespace AudioCore {
|
|
|
|
class BehaviorInfo;
|
|
|
|
|
|
|
|
class EdgeMatrix {
|
|
|
|
public:
|
|
|
|
EdgeMatrix();
|
|
|
|
~EdgeMatrix();
|
|
|
|
|
|
|
|
void Initialize(std::size_t _node_count);
|
|
|
|
bool Connected(s32 a, s32 b);
|
|
|
|
void Connect(s32 a, s32 b);
|
|
|
|
void Disconnect(s32 a, s32 b);
|
|
|
|
void RemoveEdges(s32 edge);
|
|
|
|
std::size_t GetNodeCount() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void SetState(s32 a, s32 b, bool state);
|
|
|
|
bool GetState(s32 a, s32 b);
|
|
|
|
|
|
|
|
bool InRange(s32 a, s32 b) const;
|
|
|
|
std::vector<bool> edge_matrix{};
|
|
|
|
std::size_t node_count{};
|
|
|
|
};
|
|
|
|
|
|
|
|
class NodeStates {
|
|
|
|
public:
|
|
|
|
enum class State {
|
|
|
|
NoState = 0,
|
|
|
|
InFound = 1,
|
|
|
|
InCompleted = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Looks to be a fixed size stack. Placed within the NodeStates class based on symbols
|
|
|
|
class Stack {
|
|
|
|
public:
|
|
|
|
Stack();
|
|
|
|
~Stack();
|
|
|
|
|
|
|
|
void Reset(std::size_t size);
|
|
|
|
void push(s32 val);
|
|
|
|
std::size_t Count() const;
|
|
|
|
s32 top() const;
|
|
|
|
s32 pop();
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<s32> stack{};
|
|
|
|
std::size_t stack_size{};
|
|
|
|
std::size_t stack_pos{};
|
|
|
|
};
|
|
|
|
NodeStates();
|
|
|
|
~NodeStates();
|
|
|
|
|
2020-11-25 20:21:03 +00:00
|
|
|
void Initialize(std::size_t node_count_);
|
2020-07-12 12:59:14 +01:00
|
|
|
bool Tsort(EdgeMatrix& edge_matrix);
|
|
|
|
std::size_t GetIndexPos() const;
|
|
|
|
const std::vector<s32>& GetIndexList() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void PushTsortResult(s32 index);
|
|
|
|
bool DepthFirstSearch(EdgeMatrix& edge_matrix);
|
|
|
|
void ResetState();
|
2020-11-25 20:21:03 +00:00
|
|
|
void UpdateState(State state, std::size_t i);
|
|
|
|
State GetState(std::size_t i);
|
2020-07-12 12:59:14 +01:00
|
|
|
|
|
|
|
std::size_t node_count{};
|
|
|
|
std::vector<bool> was_node_found{};
|
|
|
|
std::vector<bool> was_node_completed{};
|
|
|
|
std::size_t index_pos{};
|
|
|
|
std::vector<s32> index_list{};
|
2020-11-25 20:21:03 +00:00
|
|
|
Stack index_stack{};
|
2020-07-12 12:59:14 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class SplitterMagic : u32_le {
|
|
|
|
SplitterHeader = Common::MakeMagic('S', 'N', 'D', 'H'),
|
|
|
|
DataHeader = Common::MakeMagic('S', 'N', 'D', 'D'),
|
|
|
|
InfoHeader = Common::MakeMagic('S', 'N', 'D', 'I'),
|
|
|
|
};
|
|
|
|
|
|
|
|
class SplitterInfo {
|
|
|
|
public:
|
|
|
|
struct InHeader {
|
|
|
|
SplitterMagic magic{};
|
|
|
|
s32_le info_count{};
|
|
|
|
s32_le data_count{};
|
|
|
|
INSERT_PADDING_WORDS(5);
|
|
|
|
};
|
2020-11-25 20:21:03 +00:00
|
|
|
static_assert(sizeof(InHeader) == 0x20, "SplitterInfo::InHeader is an invalid size");
|
2020-07-12 12:59:14 +01:00
|
|
|
|
|
|
|
struct InInfoPrams {
|
|
|
|
SplitterMagic magic{};
|
|
|
|
s32_le send_id{};
|
|
|
|
s32_le sample_rate{};
|
|
|
|
s32_le length{};
|
|
|
|
s32_le resource_id_base{};
|
|
|
|
};
|
2020-11-25 20:21:03 +00:00
|
|
|
static_assert(sizeof(InInfoPrams) == 0x14, "SplitterInfo::InInfoPrams is an invalid size");
|
2020-07-12 12:59:14 +01:00
|
|
|
|
|
|
|
struct InDestinationParams {
|
|
|
|
SplitterMagic magic{};
|
|
|
|
s32_le splitter_id{};
|
|
|
|
std::array<float_le, AudioCommon::MAX_MIX_BUFFERS> mix_volumes{};
|
|
|
|
s32_le mix_id{};
|
|
|
|
bool in_use{};
|
|
|
|
INSERT_PADDING_BYTES(3);
|
|
|
|
};
|
2020-11-25 20:21:03 +00:00
|
|
|
static_assert(sizeof(InDestinationParams) == 0x70,
|
2020-07-12 12:59:14 +01:00
|
|
|
"SplitterInfo::InDestinationParams is an invalid size");
|
|
|
|
};
|
|
|
|
|
|
|
|
class ServerSplitterDestinationData {
|
|
|
|
public:
|
2020-11-25 20:21:03 +00:00
|
|
|
explicit ServerSplitterDestinationData(s32 id_);
|
2020-07-12 12:59:14 +01:00
|
|
|
~ServerSplitterDestinationData();
|
|
|
|
|
|
|
|
void Update(SplitterInfo::InDestinationParams& header);
|
|
|
|
|
|
|
|
ServerSplitterDestinationData* GetNextDestination();
|
|
|
|
const ServerSplitterDestinationData* GetNextDestination() const;
|
|
|
|
void SetNextDestination(ServerSplitterDestinationData* dest);
|
|
|
|
bool ValidMixId() const;
|
|
|
|
s32 GetMixId() const;
|
|
|
|
bool IsConfigured() const;
|
|
|
|
float GetMixVolume(std::size_t i) const;
|
|
|
|
const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& CurrentMixVolumes() const;
|
|
|
|
const std::array<float, AudioCommon::MAX_MIX_BUFFERS>& LastMixVolumes() const;
|
|
|
|
void MarkDirty();
|
|
|
|
void UpdateInternalState();
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool needs_update{};
|
|
|
|
bool in_use{};
|
|
|
|
s32 id{};
|
|
|
|
s32 mix_id{};
|
|
|
|
std::array<float, AudioCommon::MAX_MIX_BUFFERS> current_mix_volumes{};
|
|
|
|
std::array<float, AudioCommon::MAX_MIX_BUFFERS> last_mix_volumes{};
|
|
|
|
ServerSplitterDestinationData* next = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ServerSplitterInfo {
|
|
|
|
public:
|
2020-11-25 20:21:03 +00:00
|
|
|
explicit ServerSplitterInfo(s32 id_);
|
2020-07-12 12:59:14 +01:00
|
|
|
~ServerSplitterInfo();
|
|
|
|
|
|
|
|
void InitializeInfos();
|
|
|
|
void ClearNewConnectionFlag();
|
|
|
|
std::size_t Update(SplitterInfo::InInfoPrams& header);
|
|
|
|
|
|
|
|
ServerSplitterDestinationData* GetHead();
|
|
|
|
const ServerSplitterDestinationData* GetHead() const;
|
|
|
|
ServerSplitterDestinationData* GetData(std::size_t depth);
|
|
|
|
const ServerSplitterDestinationData* GetData(std::size_t depth) const;
|
|
|
|
|
|
|
|
bool HasNewConnection() const;
|
|
|
|
s32 GetLength() const;
|
|
|
|
|
|
|
|
void SetHead(ServerSplitterDestinationData* new_head);
|
|
|
|
void SetHeadDepth(s32 length);
|
|
|
|
|
|
|
|
private:
|
|
|
|
s32 sample_rate{};
|
|
|
|
s32 id{};
|
|
|
|
s32 send_length{};
|
|
|
|
ServerSplitterDestinationData* head = nullptr;
|
|
|
|
bool new_connection{};
|
|
|
|
};
|
|
|
|
|
|
|
|
class SplitterContext {
|
|
|
|
public:
|
|
|
|
SplitterContext();
|
|
|
|
~SplitterContext();
|
|
|
|
|
|
|
|
void Initialize(BehaviorInfo& behavior_info, std::size_t splitter_count,
|
|
|
|
std::size_t data_count);
|
|
|
|
|
|
|
|
bool Update(const std::vector<u8>& input, std::size_t& input_offset, std::size_t& bytes_read);
|
|
|
|
bool UsingSplitter() const;
|
|
|
|
|
|
|
|
ServerSplitterInfo& GetInfo(std::size_t i);
|
|
|
|
const ServerSplitterInfo& GetInfo(std::size_t i) const;
|
|
|
|
ServerSplitterDestinationData& GetData(std::size_t i);
|
|
|
|
const ServerSplitterDestinationData& GetData(std::size_t i) const;
|
|
|
|
ServerSplitterDestinationData* GetDestinationData(std::size_t info, std::size_t data);
|
|
|
|
const ServerSplitterDestinationData* GetDestinationData(std::size_t info,
|
|
|
|
std::size_t data) const;
|
|
|
|
void UpdateInternalState();
|
|
|
|
|
|
|
|
std::size_t GetInfoCount() const;
|
|
|
|
std::size_t GetDataCount() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void Setup(std::size_t info_count, std::size_t data_count, bool is_splitter_bug_fixed);
|
|
|
|
bool UpdateInfo(const std::vector<u8>& input, std::size_t& input_offset,
|
|
|
|
std::size_t& bytes_read, s32 in_splitter_count);
|
|
|
|
bool UpdateData(const std::vector<u8>& input, std::size_t& input_offset,
|
|
|
|
std::size_t& bytes_read, s32 in_data_count);
|
|
|
|
bool RecomposeDestination(ServerSplitterInfo& info, SplitterInfo::InInfoPrams& header,
|
|
|
|
const std::vector<u8>& input, const std::size_t& input_offset);
|
|
|
|
|
|
|
|
std::vector<ServerSplitterInfo> infos{};
|
|
|
|
std::vector<ServerSplitterDestinationData> datas{};
|
|
|
|
|
|
|
|
std::size_t info_count{};
|
|
|
|
std::size_t data_count{};
|
|
|
|
bool bug_fixed{};
|
|
|
|
};
|
|
|
|
} // namespace AudioCore
|