mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-03-28 14:39:43 -06:00
* ajm: handle ParseRiffheader flag * small optimizations and cleanup * allow uninitialized instances handle RIFF * fixed audio cutoff and small refactoring * small fix to the returned data * fix gapless init, reset total samples on RIFF init * warning reporting + consume input buffer on gapless loop
109 lines
3.0 KiB
C++
109 lines
3.0 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include "common/enum.h"
|
|
#include "common/types.h"
|
|
#include "core/libraries/ajm/ajm.h"
|
|
#include "core/libraries/ajm/ajm_batch.h"
|
|
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <tuple>
|
|
|
|
namespace Libraries::Ajm {
|
|
|
|
u8 GetPCMSize(AjmFormatEncoding format);
|
|
|
|
class SparseOutputBuffer {
|
|
public:
|
|
SparseOutputBuffer(std::span<std::span<u8>> chunks)
|
|
: m_chunks(chunks), m_current(m_chunks.begin()) {}
|
|
|
|
template <class T>
|
|
size_t Write(std::span<T> pcm) {
|
|
size_t samples_written = 0;
|
|
while (!pcm.empty() && !IsEmpty()) {
|
|
auto size = std::min(pcm.size() * sizeof(T), m_current->size());
|
|
std::memcpy(m_current->data(), pcm.data(), size);
|
|
const auto nsamples = size / sizeof(T);
|
|
samples_written += nsamples;
|
|
pcm = pcm.subspan(nsamples);
|
|
*m_current = m_current->subspan(size);
|
|
if (m_current->empty()) {
|
|
++m_current;
|
|
}
|
|
}
|
|
if (!pcm.empty()) {
|
|
LOG_ERROR(Lib_Ajm, "Could not write {} samples", pcm.size());
|
|
}
|
|
return samples_written;
|
|
}
|
|
|
|
bool IsEmpty() const {
|
|
return m_current == m_chunks.end();
|
|
}
|
|
|
|
size_t Size() const {
|
|
size_t result = 0;
|
|
for (auto it = m_current; it != m_chunks.end(); ++it) {
|
|
result += it->size();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
std::span<std::span<u8>> m_chunks;
|
|
std::span<std::span<u8>>::iterator m_current;
|
|
};
|
|
|
|
struct AjmInstanceGapless {
|
|
AjmSidebandGaplessDecode init{};
|
|
AjmSidebandGaplessDecode current{};
|
|
|
|
bool IsEnd() const {
|
|
return init.total_samples != 0 && current.total_samples == 0;
|
|
}
|
|
|
|
void Reset() {
|
|
current.total_samples = init.total_samples;
|
|
current.skip_samples = init.skip_samples;
|
|
current.skipped_samples = 0;
|
|
}
|
|
};
|
|
|
|
class AjmCodec {
|
|
public:
|
|
virtual ~AjmCodec() = default;
|
|
|
|
virtual void Initialize(const void* buffer, u32 buffer_size) = 0;
|
|
virtual void Reset() = 0;
|
|
virtual void GetInfo(void* out_info) const = 0;
|
|
virtual AjmSidebandFormat GetFormat() const = 0;
|
|
virtual u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const = 0;
|
|
virtual std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
|
AjmInstanceGapless& gapless) = 0;
|
|
};
|
|
|
|
class AjmInstance {
|
|
public:
|
|
AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags);
|
|
|
|
void ExecuteJob(AjmJob& job);
|
|
|
|
private:
|
|
bool HasEnoughSpace(const SparseOutputBuffer& output) const;
|
|
std::optional<u32> GetNumRemainingSamples() const;
|
|
void Reset();
|
|
|
|
AjmInstanceFlags m_flags{};
|
|
AjmSidebandFormat m_format{};
|
|
AjmInstanceGapless m_gapless{};
|
|
AjmSidebandResampleParameters m_resample_parameters{};
|
|
u32 m_total_samples{};
|
|
std::unique_ptr<AjmCodec> m_codec;
|
|
};
|
|
|
|
} // namespace Libraries::Ajm
|