mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 07:55:29 +03:00
Refactor Audio + Fix NV Bugs (#92)
* Fix NvHostCtrl:EventSignal event ID parsing * Divide the audout buffer length by the sample size * Correct audout channel quantity handling * A few bugfixes for audio tracks * * Correctly lock in CheckReleasedBuffers and only call the callback once * * Check if the identifier queue is empty before accessing it's iterator * Refactor audio to better fit the codestyle * Explictly specify reference when using GetReference * Fix CheckReleasedBuffers
This commit is contained in:
parent
7290a80c3e
commit
d8ccdd723e
@ -19,7 +19,7 @@ namespace skyline::audio {
|
||||
std::shared_ptr<AudioTrack> Audio::OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback) {
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
auto track = std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback);
|
||||
auto track{std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback)};
|
||||
audioTracks.push_back(track);
|
||||
|
||||
return track;
|
||||
@ -33,11 +33,12 @@ namespace skyline::audio {
|
||||
}
|
||||
|
||||
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
||||
auto destBuffer = static_cast<i16 *>(audioData);
|
||||
auto streamSamples = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
||||
size_t writtenSamples = 0;
|
||||
auto destBuffer{static_cast<i16 *>(audioData)};
|
||||
auto streamSamples{static_cast<size_t>(numFrames) * audioStream->getChannelCount()};
|
||||
size_t writtenSamples{};
|
||||
|
||||
std::unique_lock trackGuard(trackLock);
|
||||
{
|
||||
std::lock_guard trackGuard(trackLock);
|
||||
|
||||
for (auto &track : audioTracks) {
|
||||
if (track->playbackState == AudioOutState::Stopped)
|
||||
@ -54,8 +55,7 @@ namespace skyline::audio {
|
||||
track->sampleCounter += trackSamples;
|
||||
track->CheckReleasedBuffers();
|
||||
}
|
||||
|
||||
trackGuard.unlock();
|
||||
}
|
||||
|
||||
if (streamSamples > writtenSamples)
|
||||
memset(destBuffer + writtenSamples, 0, (streamSamples - writtenSamples) * sizeof(i16));
|
||||
|
@ -9,11 +9,11 @@
|
||||
namespace skyline::audio {
|
||||
AdpcmDecoder::AdpcmDecoder(const std::vector<std::array<i16, 2>> &coefficients) : coefficients(coefficients) {}
|
||||
|
||||
std::vector<i16> AdpcmDecoder::Decode(const std::vector<u8> &adpcmData) {
|
||||
constexpr size_t BytesPerFrame = 0x8; //!< The number of bytes in a single frame
|
||||
constexpr size_t SamplesPerFrame = 0xE; //!< The number of samples in a single frame
|
||||
std::vector<i16> AdpcmDecoder::Decode(std::span<u8> adpcmData) {
|
||||
constexpr size_t BytesPerFrame{0x8};
|
||||
constexpr size_t SamplesPerFrame{0xE};
|
||||
|
||||
size_t remainingSamples = (adpcmData.size() / BytesPerFrame) * SamplesPerFrame;
|
||||
size_t remainingSamples{(adpcmData.size() / BytesPerFrame) * SamplesPerFrame};
|
||||
|
||||
std::vector<i16> output;
|
||||
output.reserve(remainingSamples);
|
||||
@ -21,9 +21,9 @@ namespace skyline::audio {
|
||||
size_t inputOffset{};
|
||||
|
||||
while (inputOffset < adpcmData.size()) {
|
||||
FrameHeader header(adpcmData[inputOffset++]);
|
||||
FrameHeader header{adpcmData[inputOffset++]};
|
||||
|
||||
size_t frameSamples = std::min(SamplesPerFrame, remainingSamples);
|
||||
size_t frameSamples{std::min(SamplesPerFrame, remainingSamples)};
|
||||
|
||||
i32 ctx{};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
@ -15,14 +16,13 @@ namespace skyline::audio {
|
||||
* @brief This struct holds a single ADPCM frame header
|
||||
*/
|
||||
union FrameHeader {
|
||||
u8 raw;
|
||||
|
||||
struct {
|
||||
u8 scale : 4; //!< The scale factor for this frame
|
||||
u8 coefficientIndex : 3; //!< The index of the coeffcients to use for this frame
|
||||
u8 coefficientIndex : 3;
|
||||
u8 _pad_ :1;
|
||||
};
|
||||
u8 raw; //!< The raw value
|
||||
|
||||
FrameHeader(u8 raw) : raw(raw) {}
|
||||
};
|
||||
static_assert(sizeof(FrameHeader) == 0x1);
|
||||
|
||||
@ -37,6 +37,6 @@ namespace skyline::audio {
|
||||
* @param adpcmData A buffer containing the raw ADPCM data
|
||||
* @return A buffer containing decoded single channel I16 PCM data
|
||||
*/
|
||||
std::vector<i16> Decode(const std::vector<u8> &adpcmData);
|
||||
std::vector<i16> Decode(std::span<u8> adpcmData);
|
||||
};
|
||||
}
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
@ -142,11 +143,11 @@ namespace skyline::audio {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This appends data from a vector to the buffer
|
||||
* @param sampleData A reference to a vector containing the data to be appended
|
||||
* @brief This appends data from a span to the buffer
|
||||
* @param data A span containing the data to be appended
|
||||
*/
|
||||
inline void Append(const std::vector<Type> &data) {
|
||||
Append(const_cast<Type *>(data.data()), data.size());
|
||||
inline void Append(std::span<Type> data) {
|
||||
Append(data.data(), data.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -8,10 +8,10 @@
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr u16 SampleRate = 48000; //!< The common sampling rate to use for audio output
|
||||
constexpr u8 ChannelCount = 2; //!< The common amount of channels to use for audio output
|
||||
constexpr u16 MixBufferSize = 960; //!< The size of the mix buffer by default
|
||||
constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The common PCM data format to use for audio output
|
||||
constexpr u16 SampleRate{48000}; //!< The common sampling rate to use for audio output
|
||||
constexpr u8 ChannelCount{2}; //!< The common amount of channels to use for audio output
|
||||
constexpr u16 MixBufferSize{960}; //!< The size of the mix buffer by default
|
||||
constexpr auto PcmFormat{oboe::AudioFormat::I16}; //!< The common PCM data format to use for audio output
|
||||
};
|
||||
|
||||
namespace audio {
|
||||
@ -41,9 +41,9 @@ namespace skyline {
|
||||
* @brief This stores information about pushed buffers
|
||||
*/
|
||||
struct BufferIdentifier {
|
||||
u64 tag; //!< The tag of the buffer
|
||||
u64 finalSample; //!< The final sample this buffer will be played in
|
||||
bool released; //!< If the buffer has been released
|
||||
u64 tag;
|
||||
u64 finalSample; //!< The final sample this buffer will be played in, after that the buffer can be safely released
|
||||
bool released; //!< If the buffer has been released (fully played back)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3,17 +3,18 @@
|
||||
|
||||
#include <array>
|
||||
#include <common.h>
|
||||
#include "common.h"
|
||||
#include "resampler.h"
|
||||
|
||||
namespace skyline::audio {
|
||||
/**
|
||||
* @brief This holds the coefficients of a single output frame
|
||||
* @brief This holds the coefficients for each index of a single output frame
|
||||
*/
|
||||
struct LutEntry {
|
||||
i32 a; //!< The coefficient for the first index
|
||||
i32 b; //!< The coefficient for the second index
|
||||
i32 c; //!< The coefficient for the third index
|
||||
i32 d; //!< The coefficient for the fourth index
|
||||
i32 a;
|
||||
i32 b;
|
||||
i32 c;
|
||||
i32 d;
|
||||
};
|
||||
|
||||
// @fmt:off
|
||||
@ -51,7 +52,7 @@ namespace skyline::audio {
|
||||
{48, 7600, 19361, 5773}, {41, 7472, 19377, 5888}, {34, 7345, 19391, 6004}, {28, 7219, 19403, 6121},
|
||||
{22, 7093, 19412, 6239}, {15, 6968, 19419, 6359}, {9, 6845, 19424, 6479}, {3, 6722, 19426, 6600}}};
|
||||
|
||||
constexpr std::array<LutEntry, 128> CurveLut1 = {{
|
||||
constexpr std::array<LutEntry, 128> CurveLut1{{
|
||||
{-68, 32639, 69, -5}, {-200, 32630, 212, -15}, {-328, 32613, 359, -26}, {-450, 32586, 512, -36},
|
||||
{-568, 32551, 669, -47}, {-680, 32507, 832, -58}, {-788, 32454, 1000, -69}, {-891, 32393, 1174, -80},
|
||||
{-990, 32323, 1352, -92}, {-1084, 32244, 1536, -103}, {-1173, 32157, 1724, -115}, {-1258, 32061, 1919, -128},
|
||||
@ -85,7 +86,7 @@ namespace skyline::audio {
|
||||
{-80, 1174, 32393, -891}, {-69, 1000, 32454, -788}, {-58, 832, 32507, -680}, {-47, 669, 32551, -568},
|
||||
{-36, 512, 32586, -450}, {-26, 359, 32613, -328}, {-15, 212, 32630, -200}, {-5, 69, 32639, -68}}};
|
||||
|
||||
constexpr std::array<LutEntry, 128> CurveLut2 = {{
|
||||
constexpr std::array<LutEntry, 128> CurveLut2{{
|
||||
{3195, 26287, 3329, -32}, {3064, 26281, 3467, -34}, {2936, 26270, 3608, -38}, {2811, 26253, 3751, -42},
|
||||
{2688, 26230, 3897, -46}, {2568, 26202, 4046, -50}, {2451, 26169, 4199, -54}, {2338, 26130, 4354, -58},
|
||||
{2227, 26085, 4512, -63}, {2120, 26035, 4673, -67}, {2015, 25980, 4837, -72}, {1912, 25919, 5004, -76},
|
||||
@ -120,12 +121,12 @@ namespace skyline::audio {
|
||||
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
|
||||
// @fmt:on
|
||||
|
||||
std::vector<i16> Resampler::ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, u8 channelCount) {
|
||||
auto step = static_cast<u32>(ratio * 0x8000);
|
||||
auto outputSize = static_cast<size_t>(inputBuffer.size() / ratio);
|
||||
std::vector<i16> Resampler::ResampleBuffer(std::span<i16> inputBuffer, double ratio, u8 channelCount) {
|
||||
auto step{static_cast<u32>(ratio * 0x8000)};
|
||||
auto outputSize{static_cast<size_t>(inputBuffer.size() / ratio)};
|
||||
std::vector<i16> outputBuffer(outputSize);
|
||||
|
||||
const std::array<skyline::audio::LutEntry, 128> &lut = [step] {
|
||||
const std::array<LutEntry, 128> &lut = [step] {
|
||||
if (step > 0xAAAA)
|
||||
return CurveLut0;
|
||||
else if (step <= 0x8000)
|
||||
@ -134,19 +135,19 @@ namespace skyline::audio {
|
||||
return CurveLut2;
|
||||
}();
|
||||
|
||||
for (size_t outIndex = 0, inIndex = 0; outIndex < outputSize; outIndex += channelCount) {
|
||||
auto lutIndex = fraction >> 8;
|
||||
for (size_t outIndex{}, inIndex{}; outIndex < outputSize; outIndex += channelCount) {
|
||||
u32 lutIndex{fraction >> 8};
|
||||
|
||||
for (u8 channel = 0; channel < channelCount; channel++) {
|
||||
for (u8 channel{}; channel < channelCount; channel++) {
|
||||
i32 data = inputBuffer[(inIndex + 0) * channelCount + channel] * lut[lutIndex].a +
|
||||
inputBuffer[(inIndex + 1) * channelCount + channel] * lut[lutIndex].b +
|
||||
inputBuffer[(inIndex + 2) * channelCount + channel] * lut[lutIndex].c +
|
||||
inputBuffer[(inIndex + 3) * channelCount + channel] * lut[lutIndex].d;
|
||||
|
||||
outputBuffer[outIndex + channel] = static_cast<i16>(std::clamp(data >> 15, static_cast<i32>(std::numeric_limits<i16>::min()), static_cast<i32>(std::numeric_limits<i16>::max())));
|
||||
outputBuffer[outIndex + channel] = Saturate<i16, i32>(data >> 15);
|
||||
}
|
||||
|
||||
auto newOffset = fraction + step;
|
||||
u32 newOffset{fraction + step};
|
||||
inIndex += newOffset >> 15;
|
||||
fraction = newOffset & 0x7FFF;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::audio {
|
||||
@ -20,6 +21,6 @@ namespace skyline::audio {
|
||||
* @param ratio The conversion ratio needed
|
||||
* @param channelCount The amount of channels the buffer contains
|
||||
*/
|
||||
std::vector<i16> ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, u8 channelCount);
|
||||
std::vector<i16> ResampleBuffer(std::span<i16> inputBuffer, double ratio, u8 channelCount);
|
||||
};
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ namespace skyline::audio {
|
||||
|
||||
std::vector<u64> AudioTrack::GetReleasedBuffers(u32 max) {
|
||||
std::vector<u64> bufferIds;
|
||||
std::unique_lock trackGuard(bufferLock);
|
||||
std::lock_guard trackGuard(bufferLock);
|
||||
|
||||
for (u32 index = 0; index < max; index++) {
|
||||
if (!identifiers.back().released)
|
||||
for (u32 index{}; index < max; index++) {
|
||||
if (identifiers.empty() || !identifiers.back().released)
|
||||
break;
|
||||
bufferIds.push_back(identifiers.back().tag);
|
||||
identifiers.pop_back();
|
||||
@ -44,29 +44,30 @@ namespace skyline::audio {
|
||||
return bufferIds;
|
||||
}
|
||||
|
||||
void AudioTrack::AppendBuffer(u64 tag, const i16 *address, u64 size) {
|
||||
BufferIdentifier identifier;
|
||||
|
||||
identifier.released = false;
|
||||
identifier.tag = tag;
|
||||
|
||||
if (identifiers.empty())
|
||||
identifier.finalSample = size;
|
||||
else
|
||||
identifier.finalSample = size + identifiers.front().finalSample;
|
||||
void AudioTrack::AppendBuffer(u64 tag, std::span<i16> buffer) {
|
||||
BufferIdentifier identifier{
|
||||
.released = false,
|
||||
.tag = tag,
|
||||
.finalSample = identifiers.empty() ? (buffer.size()) : (buffer.size() + identifiers.front().finalSample)
|
||||
};
|
||||
|
||||
std::lock_guard guard(bufferLock);
|
||||
|
||||
identifiers.push_front(identifier);
|
||||
samples.Append(const_cast<i16 *>(address), size);
|
||||
samples.Append(buffer);
|
||||
}
|
||||
|
||||
void AudioTrack::CheckReleasedBuffers() {
|
||||
bool anyReleased{};
|
||||
|
||||
for (auto &identifier : identifiers) {
|
||||
if (identifier.finalSample <= sampleCounter && !identifier.released) {
|
||||
releaseCallback();
|
||||
anyReleased = true;
|
||||
identifier.released = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyReleased)
|
||||
releaseCallback();
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <queue>
|
||||
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <common.h>
|
||||
#include "common.h"
|
||||
@ -18,15 +18,15 @@ namespace skyline::audio {
|
||||
std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
||||
std::deque<BufferIdentifier> identifiers; //!< Queue of all appended buffer identifiers
|
||||
|
||||
u8 channelCount; //!< The amount channels present in the track
|
||||
u32 sampleRate; //!< The sample rate of the track
|
||||
u8 channelCount;
|
||||
u32 sampleRate;
|
||||
|
||||
public:
|
||||
CircularBuffer<i16, constant::SampleRate * constant::ChannelCount * 10> samples; //!< A vector of all appended audio samples
|
||||
CircularBuffer<i16, constant::SampleRate * constant::ChannelCount * 10> samples; //!< A circular buffer with all appended audio samples
|
||||
Mutex bufferLock; //!< This mutex ensures that appending to buffers doesn't overlap
|
||||
|
||||
AudioOutState playbackState{AudioOutState::Stopped}; //!< The current state of playback
|
||||
u64 sampleCounter{}; //!< A counter used for tracking buffer status
|
||||
u64 sampleCounter{}; //!< A counter used for tracking when buffers have been played and can be released
|
||||
|
||||
/**
|
||||
* @param channelCount The amount channels that will be present in the track
|
||||
@ -64,22 +64,13 @@ namespace skyline::audio {
|
||||
/**
|
||||
* @brief Appends audio samples to the output buffer
|
||||
* @param tag The tag of the buffer
|
||||
* @param address The address of the audio buffer
|
||||
* @param size The size of the audio buffer in i16 units
|
||||
* @param buffer A span containing the source sample buffer
|
||||
*/
|
||||
void AppendBuffer(u64 tag, const i16 *address, u64 size);
|
||||
|
||||
/**
|
||||
* @brief Appends audio samples to the output buffer
|
||||
* @param tag The tag of the buffer
|
||||
* @param sampleData A reference to a vector containing I16 format PCM data
|
||||
*/
|
||||
void AppendBuffer(u64 tag, const std::vector<i16> &sampleData = {}) {
|
||||
AppendBuffer(tag, sampleData.data(), sampleData.size());
|
||||
}
|
||||
void AppendBuffer(u64 tag, std::span<i16> buffer = {});
|
||||
|
||||
/**
|
||||
* @brief Checks if any buffers have been released and calls the appropriate callback for them
|
||||
* @note bufferLock MUST be locked when calling this
|
||||
*/
|
||||
void CheckReleasedBuffers();
|
||||
};
|
||||
|
@ -40,7 +40,7 @@ namespace skyline::service::audio {
|
||||
}
|
||||
|
||||
void IAudioDevice::QueryAudioDeviceSystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto handle = state.process->InsertItem(systemEvent);
|
||||
auto handle{state.process->InsertItem(systemEvent)};
|
||||
state.logger->Debug("Audio Device System Event Handle: 0x{:X}", handle);
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
|
@ -44,32 +44,29 @@ namespace skyline::service::audio {
|
||||
u64 sampleCapacity;
|
||||
u64 sampleSize;
|
||||
u64 sampleOffset;
|
||||
} data = state.process->GetObject<Data>(request.inputBuf.at(0).address);
|
||||
} &data{state.process->GetReference<Data>(request.inputBuf.at(0).address)};
|
||||
auto tag = request.Pop<u64>();
|
||||
|
||||
state.logger->Debug("IAudioOut: Appending buffer with address: 0x{:X}, size: 0x{:X}", data.sampleBufferPtr, data.sampleSize);
|
||||
|
||||
if (sampleRate != constant::SampleRate) {
|
||||
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
|
||||
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
|
||||
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
|
||||
|
||||
track->AppendBuffer(tag, tmpSampleBuffer);
|
||||
auto resampledBuffer = resampler.ResampleBuffer(std::span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)), static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
|
||||
track->AppendBuffer(tag, resampledBuffer);
|
||||
} else {
|
||||
track->AppendBuffer(tag, state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize);
|
||||
track->AppendBuffer(tag, std::span(state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize / sizeof(i16)));
|
||||
}
|
||||
}
|
||||
|
||||
void IAudioOut::RegisterBufferEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto handle = state.process->InsertItem(releaseEvent);
|
||||
auto handle{state.process->InsertItem(releaseEvent)};
|
||||
state.logger->Debug("IAudioOut: Buffer Release Event Handle: 0x{:X}", handle);
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
|
||||
void IAudioOut::GetReleasedAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto maxCount = static_cast<u32>(request.outputBuf.at(0).size >> 3);
|
||||
std::vector<u64> releasedBuffers = track->GetReleasedBuffers(maxCount);
|
||||
auto count = static_cast<u32>(releasedBuffers.size());
|
||||
auto maxCount{static_cast<u32>(request.outputBuf.at(0).size >> 3)};
|
||||
std::vector<u64> releasedBuffers{track->GetReleasedBuffers(maxCount)};
|
||||
auto count{static_cast<u32>(releasedBuffers.size())};
|
||||
|
||||
// Fill rest of output buffer with zeros
|
||||
releasedBuffers.resize(maxCount, 0);
|
||||
@ -79,7 +76,7 @@ namespace skyline::service::audio {
|
||||
}
|
||||
|
||||
void IAudioOut::ContainsAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto tag = request.Pop<u64>();
|
||||
auto tag{request.Pop<u64>()};
|
||||
|
||||
response.Push(static_cast<u32>(track->ContainsBuffer(tag)));
|
||||
}
|
||||
|
@ -18,10 +18,9 @@ namespace skyline::service::audio {
|
||||
skyline::audio::Resampler resampler; //!< The audio resampler object used to resample audio
|
||||
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio out
|
||||
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
|
||||
std::vector<i16> tmpSampleBuffer; //!< A temporary buffer used to store sample data in AppendAudioOutBuffer
|
||||
|
||||
const u32 sampleRate; //!< The sample rate of the audio out
|
||||
const u8 channelCount; //!< The amount of channels in the data sent to the audio out
|
||||
u32 sampleRate;
|
||||
u8 channelCount;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -18,14 +18,13 @@ namespace skyline::service::audio {
|
||||
}
|
||||
|
||||
void IAudioOutManager::OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
u32 sampleRate = request.Pop<u32>();
|
||||
request.Pop<u16>(); // Channel count is stored in the upper half of a u32
|
||||
u16 channelCount = request.Pop<u16>();
|
||||
auto sampleRate{request.Pop<u32>()};
|
||||
auto channelCount{static_cast<u16>(request.Pop<u32>())};
|
||||
|
||||
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
|
||||
state.logger->Debug("Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
|
||||
|
||||
sampleRate = sampleRate ? sampleRate : constant::SampleRate;
|
||||
channelCount = channelCount ? channelCount : static_cast<u16>(constant::ChannelCount);
|
||||
channelCount = channelCount ? channelCount : constant::ChannelCount;
|
||||
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
|
||||
|
||||
response.Push<u32>(sampleRate);
|
||||
|
@ -51,14 +51,14 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
}
|
||||
|
||||
void IAudioRenderer::RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto inputAddress = request.inputBuf.at(0).address;
|
||||
auto inputAddress{request.inputBuf.at(0).address};
|
||||
|
||||
auto inputHeader = state.process->GetObject<UpdateDataHeader>(inputAddress);
|
||||
auto inputHeader{state.process->GetObject<UpdateDataHeader>(inputAddress)};
|
||||
revisionInfo.SetUserRevision(inputHeader.revision);
|
||||
inputAddress += sizeof(UpdateDataHeader);
|
||||
inputAddress += inputHeader.behaviorSize; // Unused
|
||||
|
||||
auto memoryPoolCount = memoryPools.size();
|
||||
auto memoryPoolCount{memoryPools.size()};
|
||||
std::vector<MemoryPoolIn> memoryPoolsIn(memoryPoolCount);
|
||||
state.process->ReadMemory(memoryPoolsIn.data(), inputAddress, memoryPoolCount * sizeof(MemoryPoolIn));
|
||||
inputAddress += inputHeader.memoryPoolSize;
|
||||
@ -128,11 +128,11 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
}
|
||||
|
||||
void IAudioRenderer::UpdateAudio() {
|
||||
auto released = track->GetReleasedBuffers(2);
|
||||
auto released{track->GetReleasedBuffers(2)};
|
||||
|
||||
for (auto &tag : released) {
|
||||
MixFinalBuffer();
|
||||
track->AppendBuffer(tag, sampleBuffer.data(), sampleBuffer.size());
|
||||
track->AppendBuffer(tag, sampleBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,14 +149,14 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
while (pendingSamples > 0) {
|
||||
u32 voiceBufferOffset{};
|
||||
u32 voiceBufferSize{};
|
||||
auto &voiceSamples = voice.GetBufferData(pendingSamples, voiceBufferOffset, voiceBufferSize);
|
||||
auto &voiceSamples{voice.GetBufferData(pendingSamples, voiceBufferOffset, voiceBufferSize)};
|
||||
|
||||
if (voiceBufferSize == 0)
|
||||
break;
|
||||
|
||||
pendingSamples -= voiceBufferSize / constant::ChannelCount;
|
||||
|
||||
for (auto index = voiceBufferOffset; index < voiceBufferOffset + voiceBufferSize; index++) {
|
||||
for (auto index{voiceBufferOffset}; index < voiceBufferOffset + voiceBufferSize; index++) {
|
||||
if (writtenSamples == bufferOffset) {
|
||||
sampleBuffer[bufferOffset] = skyline::audio::Saturate<i16, i32>(voiceSamples[index] * voice.volume);
|
||||
|
||||
@ -180,7 +180,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
}
|
||||
|
||||
void IAudioRenderer::QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto handle = state.process->InsertItem(systemEvent);
|
||||
auto handle{state.process->InsertItem(systemEvent)};
|
||||
state.logger->Debug("Audren System Event Handle: 0x{:X}", handle);
|
||||
response.copyHandles.push_back(handle);
|
||||
}
|
||||
|
@ -22,39 +22,39 @@ namespace skyline {
|
||||
* @brief The parameters used to configure an IAudioRenderer
|
||||
*/
|
||||
struct AudioRendererParameters {
|
||||
u32 sampleRate; //!< The sample rate to use for the renderer
|
||||
u32 sampleCount; //!< The buffer sample count
|
||||
u32 mixBufferCount; //!< The amount of mix buffers to use
|
||||
u32 subMixCount; //!< The amount of sub mixes to use
|
||||
u32 voiceCount; //!< The amount of voices to use
|
||||
u32 sinkCount; //!< The amount of sinks to use
|
||||
u32 effectCount; //!< The amount of effects to use
|
||||
u32 performanceManagerCount; //!< The amount of performance managers to use
|
||||
u32 voiceDropEnable; //!< Whether to enable voice drop
|
||||
u32 splitterCount; //!< The amount of splitters to use
|
||||
u32 splitterDestinationDataCount; //!< The amount of splitter destination outputs to use
|
||||
u32 sampleRate;
|
||||
u32 sampleCount;
|
||||
u32 mixBufferCount;
|
||||
u32 subMixCount;
|
||||
u32 voiceCount;
|
||||
u32 sinkCount;
|
||||
u32 effectCount;
|
||||
u32 performanceManagerCount;
|
||||
u32 voiceDropEnable;
|
||||
u32 splitterCount;
|
||||
u32 splitterDestinationDataCount;
|
||||
u32 _unk0_;
|
||||
u32 revision; //!< The revision of audren to use
|
||||
u32 revision;
|
||||
};
|
||||
static_assert(sizeof(AudioRendererParameters) == 0x34);
|
||||
|
||||
/**
|
||||
* @brief Header containing information about the software side audren implementation
|
||||
* @brief Header containing information about the software side audren implementation and the sizes of all input data
|
||||
*/
|
||||
struct UpdateDataHeader {
|
||||
u32 revision; //!< Revision of the software implementation
|
||||
u32 behaviorSize; //!< The total size of the behaviour info
|
||||
u32 memoryPoolSize; //!< The total size of all MemoryPoolIn structs
|
||||
u32 voiceSize; //!< The total size of all VoiceIn structs
|
||||
u32 voiceResourceSize; //!< The total size of the voice resources
|
||||
u32 effectSize; //!< The total size of all EffectIn structs
|
||||
u32 mixSize; //!< The total size of all mixer descriptors in the input
|
||||
u32 sinkSize; //!< The total size of all sink descriptors in the input
|
||||
u32 performanceManagerSize; //!< The total size of all performance manager descriptors in the input
|
||||
u32 revision;
|
||||
u32 behaviorSize;
|
||||
u32 memoryPoolSize;
|
||||
u32 voiceSize;
|
||||
u32 voiceResourceSize;
|
||||
u32 effectSize;
|
||||
u32 mixSize;
|
||||
u32 sinkSize;
|
||||
u32 performanceManagerSize;
|
||||
u32 _unk0_;
|
||||
u32 elapsedFrameCountInfoSize; //!< The total size of all the elapsed frame info
|
||||
u32 elapsedFrameCountInfoSize;
|
||||
u32 _unk1_[4];
|
||||
u32 totalSize; //!< The total size of the whole input
|
||||
u32 totalSize;
|
||||
};
|
||||
static_assert(sizeof(UpdateDataHeader) == 0x40);
|
||||
|
||||
@ -63,15 +63,15 @@ namespace skyline {
|
||||
*/
|
||||
class IAudioRenderer : public BaseService {
|
||||
private:
|
||||
AudioRendererParameters parameters; //!< The parameters to use for the renderer
|
||||
AudioRendererParameters parameters;
|
||||
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
|
||||
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio renderer
|
||||
std::shared_ptr<type::KEvent> systemEvent; //!< The KEvent that is signalled when the DSP has processed all the commands
|
||||
std::vector<MemoryPool> memoryPools; //!< An vector of all memory pools that the guest may need
|
||||
std::vector<Effect> effects; //!< An vector of all effects that the guest may need
|
||||
std::vector<Voice> voices; //!< An vector of all voices that the guest may need
|
||||
std::vector<MemoryPool> memoryPools;
|
||||
std::vector<Effect> effects;
|
||||
std::vector<Voice> voices;
|
||||
std::array<i16, constant::MixBufferSize * constant::ChannelCount> sampleBuffer{}; //!< The final output data that is appended to the stream
|
||||
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
|
||||
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped};
|
||||
|
||||
/**
|
||||
* @brief Obtains new sample data from voices and mixes it together into the sample buffer
|
||||
|
@ -11,7 +11,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
*/
|
||||
enum class EffectState : u8 {
|
||||
None = 0, //!< The effect isn't being used
|
||||
New = 1 //!< The effect is new
|
||||
New = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -28,7 +28,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This is returned to inform the guest of the state of an effect
|
||||
*/
|
||||
struct EffectOut {
|
||||
EffectState state; //!< The state of the effect
|
||||
EffectState state;
|
||||
u8 _pad0_[15];
|
||||
};
|
||||
static_assert(sizeof(EffectOut) == 0x10);
|
||||
@ -38,7 +38,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
*/
|
||||
class Effect {
|
||||
public:
|
||||
EffectOut output{}; //!< The current output state
|
||||
EffectOut output{};
|
||||
|
||||
inline void ProcessInput(const EffectIn &input) {
|
||||
if (input.isNew)
|
||||
|
@ -10,22 +10,22 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This enumerates various states a memory pool can be in
|
||||
*/
|
||||
enum class MemoryPoolState : u32 {
|
||||
Invalid = 0, //!< The memory pool is invalid
|
||||
Unknown = 1, //!< The memory pool is in an unknown state
|
||||
RequestDetach = 2, //!< The memory pool should be detached from
|
||||
Detached = 3, //!< The memory pool has been detached from
|
||||
RequestAttach = 4, //!< The memory pool should be attached to
|
||||
Attached = 5, //!< The memory pool has been attached to
|
||||
Released = 6 //!< The memory pool has been released
|
||||
Invalid = 0,
|
||||
Unknown = 1,
|
||||
RequestDetach = 2,
|
||||
Detached = 3,
|
||||
RequestAttach = 4,
|
||||
Attached = 5,
|
||||
Released = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is in input containing information about a memory pool for use by the dsp
|
||||
*/
|
||||
struct MemoryPoolIn {
|
||||
u64 address; //!< The address of the memory pool
|
||||
u64 size; //!< The size of the memory pool
|
||||
MemoryPoolState state; //!< The state that is requested for the memory pool
|
||||
u64 address;
|
||||
u64 size;
|
||||
MemoryPoolState state;
|
||||
u32 _unk0_;
|
||||
u64 _unk1_;
|
||||
};
|
||||
@ -35,7 +35,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This is returned to inform the guest of the state of a memory pool
|
||||
*/
|
||||
struct MemoryPoolOut {
|
||||
MemoryPoolState state = MemoryPoolState::Detached; //!< The state of the memory pool
|
||||
MemoryPoolState state = MemoryPoolState::Detached;
|
||||
u32 _unk0_;
|
||||
u64 _unk1_;
|
||||
};
|
||||
@ -46,7 +46,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
*/
|
||||
class MemoryPool {
|
||||
public:
|
||||
MemoryPoolOut output{}; //!< The current output state
|
||||
MemoryPoolOut output{};
|
||||
|
||||
/**
|
||||
* @brief Processes the input memory pool data from the guest and sets internal data based off it
|
||||
|
@ -7,16 +7,16 @@
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
|
||||
constexpr u32 Rev0Magic = util::MakeMagic<u32>("REV0"); //!< The HOS 1.0 revision magic
|
||||
constexpr u32 RevMagic = Rev0Magic + (SupportedRevision << 24); //!< The revision magic for our supported revision
|
||||
constexpr u32 SupportedRevision{7}; //!< The audren revision our implementation supports
|
||||
constexpr u32 Rev0Magic{util::MakeMagic<u32>("REV0")}; //!< The HOS 1.0 revision magic
|
||||
constexpr u32 RevMagic{Rev0Magic + (SupportedRevision << 24)}; //!< The revision magic for our supported revision
|
||||
|
||||
namespace supportTags {
|
||||
constexpr u32 Splitter = 2; //!< The revision splitter support was added
|
||||
constexpr u32 SplitterBugFix = 5; //!< The revision the splitter buffer was made aligned
|
||||
constexpr u32 PerformanceMetricsDataFormatV2 = 5; //!< The revision a new performance metrics format is used
|
||||
constexpr u32 VaradicCommandBufferSize = 5; //!< The revision support for varying command buffer sizes was added
|
||||
constexpr u32 ElapsedFrameCount = 5; //!< The revision support for counting elapsed frames was added
|
||||
constexpr u32 Splitter{2}; //!< The revision splitter support was added
|
||||
constexpr u32 SplitterBugFix{5}; //!< The revision the splitter buffer was made aligned
|
||||
constexpr u32 PerformanceMetricsDataFormatV2{5}; //!< The revision a new performance metrics format is used
|
||||
constexpr u32 VaradicCommandBufferSize{5}; //!< The revision support for varying command buffer sizes was added
|
||||
constexpr u32 ElapsedFrameCount{5}; //!< The revision support for counting elapsed frames was added
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
void Voice::SetWaveBufferIndex(u8 index) {
|
||||
bufferIndex = static_cast<u8>(index & 3);
|
||||
bufferIndex = index & 3;
|
||||
bufferReload = true;
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
}
|
||||
|
||||
void Voice::UpdateBuffers() {
|
||||
const auto ¤tBuffer = waveBuffers.at(bufferIndex);
|
||||
const auto ¤tBuffer{waveBuffers.at(bufferIndex)};
|
||||
|
||||
if (currentBuffer.size == 0)
|
||||
return;
|
||||
@ -68,9 +68,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
state.process->ReadMemory(samples.data(), currentBuffer.address, currentBuffer.size);
|
||||
break;
|
||||
case skyline::audio::AudioFormat::ADPCM: {
|
||||
std::vector<u8> adpcmData(currentBuffer.size);
|
||||
state.process->ReadMemory(adpcmData.data(), currentBuffer.address, currentBuffer.size);
|
||||
samples = adpcmDecoder->Decode(adpcmData);
|
||||
samples = adpcmDecoder->Decode(std::span(state.process->GetPointer<u8>(currentBuffer.address), currentBuffer.size));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -81,19 +79,19 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
samples = resampler.ResampleBuffer(samples, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
|
||||
|
||||
if (channelCount == 1 && constant::ChannelCount != channelCount) {
|
||||
auto originalSize = samples.size();
|
||||
auto originalSize{samples.size()};
|
||||
samples.resize((originalSize / channelCount) * constant::ChannelCount);
|
||||
|
||||
for (auto monoIndex = originalSize - 1, targetIndex = samples.size(); monoIndex > 0; monoIndex--) {
|
||||
auto sample = samples[monoIndex];
|
||||
for (auto i = 0; i < constant::ChannelCount; i++)
|
||||
for (auto monoIndex{originalSize - 1}, targetIndex{samples.size()}; monoIndex > 0; monoIndex--) {
|
||||
auto sample{samples[monoIndex]};
|
||||
for (u8 i{}; i < constant::ChannelCount; i++)
|
||||
samples[--targetIndex] = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<i16> &Voice::GetBufferData(u32 maxSamples, u32 &outOffset, u32 &outSize) {
|
||||
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
||||
auto ¤tBuffer{waveBuffers.at(bufferIndex)};
|
||||
|
||||
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
|
||||
outSize = 0;
|
||||
|
@ -14,13 +14,13 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This stores data for configuring a biquadratic filter
|
||||
*/
|
||||
struct BiquadFilter {
|
||||
u8 enable; //!< Whether to enable the filter
|
||||
u8 enable;
|
||||
u8 _pad0_;
|
||||
u16 b0; //!< The b0 constant
|
||||
u16 b1; //!< The b1 constant
|
||||
u16 b2; //!< The b2 constant
|
||||
u16 a1; //!< The a1 constant
|
||||
u16 a2; //!< The a2 constant
|
||||
u16 b0;
|
||||
u16 b1;
|
||||
u16 b2;
|
||||
u16 a1;
|
||||
u16 a2;
|
||||
};
|
||||
static_assert(sizeof(BiquadFilter) == 0xC);
|
||||
|
||||
@ -28,16 +28,16 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This stores information of a wave buffer of samples
|
||||
*/
|
||||
struct WaveBuffer {
|
||||
u64 address; //!< The address of the wave buffer in guest memory
|
||||
u64 size; //!< The size of the wave buffer
|
||||
u32 firstSampleOffset; //!< The offset of the first sample in the buffer
|
||||
u32 lastSampleOffset; //!< The offset of the last sample in the buffer
|
||||
u64 address;
|
||||
u64 size;
|
||||
u32 firstSampleOffset;
|
||||
u32 lastSampleOffset;
|
||||
u8 looping; //!< Whether to loop the buffer
|
||||
u8 lastBuffer; //!< Whether this is the last populated buffer
|
||||
u16 _unk0_;
|
||||
u32 _unk1_;
|
||||
u64 adpcmLoopContextPosition; //!< The position of the ADPCM loop context data
|
||||
u64 adpcmLoopContextSize; //!< The size of the ADPCM loop context data
|
||||
u64 adpcmLoopContextPosition;
|
||||
u64 adpcmLoopContextSize;
|
||||
u64 _unk2_;
|
||||
};
|
||||
static_assert(sizeof(WaveBuffer) == 0x38);
|
||||
@ -46,28 +46,28 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This is in input containing the configuration of a voice
|
||||
*/
|
||||
struct VoiceIn {
|
||||
u32 slot; //!< The slot of the voice
|
||||
u32 nodeId; //!< The node ID of the voice
|
||||
u8 firstUpdate; //!< Whether this voice is new
|
||||
u32 slot;
|
||||
u32 nodeId;
|
||||
u8 firstUpdate; //!< Whether this voice is newly added
|
||||
u8 acquired; //!< Whether the sample is in use
|
||||
skyline::audio::AudioOutState playbackState; //!< The playback state
|
||||
skyline::audio::AudioFormat format; //!< The sample format
|
||||
u32 sampleRate; //!< The sample rate
|
||||
u32 priority; //!< The priority for this voice
|
||||
skyline::audio::AudioOutState playbackState;
|
||||
skyline::audio::AudioFormat format;
|
||||
u32 sampleRate;
|
||||
u32 priority;
|
||||
u32 _unk0_;
|
||||
u32 channelCount; //!< The amount of channels the wave buffers contain
|
||||
float pitch; //!< The pitch to play wave data at
|
||||
float volume; //!< The volume to play wave data at
|
||||
std::array<BiquadFilter, 2> biquadFilters; //!< Biquadratic filter configurations
|
||||
u32 appendedWaveBuffersCount; //!< The amount of buffers appended
|
||||
u32 baseWaveBufferIndex; //!< The start index of the buffer to use
|
||||
u32 channelCount;
|
||||
float pitch;
|
||||
float volume;
|
||||
std::array<BiquadFilter, 2> biquadFilters;
|
||||
u32 appendedWaveBuffersCount;
|
||||
u32 baseWaveBufferIndex;
|
||||
u32 _unk1_;
|
||||
u64 adpcmCoeffsPosition; //!< The ADPCM coefficient position in wave data
|
||||
u64 adpcmCoeffsSize; //!< The size of the ADPCM coefficient configuration data
|
||||
u32 destination; //!< The voice destination address
|
||||
u64 adpcmCoeffsPosition;
|
||||
u64 adpcmCoeffsSize;
|
||||
u32 destination;
|
||||
u32 _pad0_;
|
||||
std::array<WaveBuffer, 4> waveBuffers; //!< The wave buffers for the voice
|
||||
std::array<u32, 6> voiceChannelResourceIds; //!< A list of IDs corresponding to each channel
|
||||
std::array<WaveBuffer, 4> waveBuffers;
|
||||
std::array<u32, 6> voiceChannelResourceIds;
|
||||
u32 _pad1_[6];
|
||||
};
|
||||
static_assert(sizeof(VoiceIn) == 0x170);
|
||||
@ -77,8 +77,8 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
* @brief This is returned to inform the guest of the state of a voice
|
||||
*/
|
||||
struct VoiceOut {
|
||||
u64 playedSamplesCount; //!< The amount of samples played
|
||||
u32 playedWaveBuffersCount; //!< The amount of wave buffers fully played
|
||||
u64 playedSamplesCount;
|
||||
u32 playedWaveBuffersCount;
|
||||
u32 voiceDropsCount; //!< The amount of time audio frames have been dropped due to the rendering time limit
|
||||
};
|
||||
static_assert(sizeof(VoiceOut) == 0x10);
|
||||
@ -88,20 +88,20 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
*/
|
||||
class Voice {
|
||||
private:
|
||||
const DeviceState &state; //!< The emulator state object
|
||||
std::array<WaveBuffer, 4> waveBuffers; //!< An array containing the state of all four wave buffers
|
||||
const DeviceState &state;
|
||||
std::array<WaveBuffer, 4> waveBuffers;
|
||||
std::vector<i16> samples; //!< A vector containing processed sample data
|
||||
skyline::audio::Resampler resampler; //!< The resampler object used for changing the sample rate of a stream
|
||||
std::optional<skyline::audio::AdpcmDecoder> adpcmDecoder; //!< The decoder object used for decoding ADPCM encoded samples
|
||||
skyline::audio::Resampler resampler; //!< The resampler object used for changing the sample rate of a wave buffer's stream
|
||||
std::optional<skyline::audio::AdpcmDecoder> adpcmDecoder;
|
||||
|
||||
bool acquired{false}; //!< If the voice is in use
|
||||
bool bufferReload{true}; //!< If the buffer needs to be updated
|
||||
bool bufferReload{true};
|
||||
u8 bufferIndex{}; //!< The index of the wave buffer currently in use
|
||||
u32 sampleOffset{}; //!< The offset in the sample data of the current wave buffer
|
||||
u32 sampleRate{}; //!< The sample rate of the sample data
|
||||
u8 channelCount{}; //!< The amount of channels in the sample data
|
||||
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The playback state of the voice
|
||||
skyline::audio::AudioFormat format{skyline::audio::AudioFormat::Invalid}; //!< The format used for guest audio data
|
||||
u32 sampleRate{};
|
||||
u8 channelCount{};
|
||||
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped};
|
||||
skyline::audio::AudioFormat format{skyline::audio::AudioFormat::Invalid};
|
||||
|
||||
/**
|
||||
* @brief This updates the sample buffer with data from the current wave buffer and processes it
|
||||
@ -115,8 +115,8 @@ namespace skyline::service::audio::IAudioRenderer {
|
||||
void SetWaveBufferIndex(u8 index);
|
||||
|
||||
public:
|
||||
VoiceOut output{}; //!< The current output state
|
||||
float volume{}; //!< The volume of the voice
|
||||
VoiceOut output{};
|
||||
float volume{};
|
||||
|
||||
Voice(const DeviceState &state);
|
||||
|
||||
|
@ -28,24 +28,24 @@ namespace skyline::service::audio {
|
||||
IAudioRenderer::RevisionInfo revisionInfo{};
|
||||
revisionInfo.SetUserRevision(params.revision);
|
||||
|
||||
u32 totalMixCount = params.subMixCount + 1;
|
||||
u32 totalMixCount{params.subMixCount + 1};
|
||||
|
||||
i64 size = util::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
|
||||
i64 size{util::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
|
||||
params.subMixCount * 0x400 +
|
||||
totalMixCount * 0x940 +
|
||||
params.voiceCount * 0x3F0 +
|
||||
util::AlignUp(totalMixCount * 8, 16) +
|
||||
util::AlignUp(params.voiceCount * 8, 16) +
|
||||
util::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) + (params.sinkCount + params.subMixCount) * 0x2C0 + (params.effectCount + params.voiceCount * 4) * 0x30 + 0x50;
|
||||
util::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) + (params.sinkCount + params.subMixCount) * 0x2C0 + (params.effectCount + params.voiceCount * 4) * 0x30 + 0x50};
|
||||
|
||||
if (revisionInfo.SplitterSupported()) {
|
||||
i32 nodeStateWorkSize = util::AlignUp(totalMixCount, constant::BufferAlignment);
|
||||
i32 nodeStateWorkSize{util::AlignUp<i32>(totalMixCount, constant::BufferAlignment)};
|
||||
if (nodeStateWorkSize < 0)
|
||||
nodeStateWorkSize |= 7;
|
||||
|
||||
nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8);
|
||||
|
||||
i32 edgeMatrixWorkSize = util::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment);
|
||||
i32 edgeMatrixWorkSize{util::AlignUp<i32>(totalMixCount * totalMixCount, constant::BufferAlignment)};
|
||||
if (edgeMatrixWorkSize < 0)
|
||||
edgeMatrixWorkSize |= 7;
|
||||
|
||||
@ -53,7 +53,7 @@ namespace skyline::service::audio {
|
||||
size += util::AlignUp(edgeMatrixWorkSize + nodeStateWorkSize, 16);
|
||||
}
|
||||
|
||||
i64 splitterWorkSize = 0;
|
||||
i64 splitterWorkSize{};
|
||||
|
||||
if (revisionInfo.SplitterSupported()) {
|
||||
splitterWorkSize += params.splitterDestinationDataCount * 0xE0 + params.splitterCount * 0x20;
|
||||
@ -65,7 +65,7 @@ namespace skyline::service::audio {
|
||||
size = params.sinkCount * 0x170 + (params.sinkCount + params.subMixCount) * 0x280 + params.effectCount * 0x4C0 + ((size + splitterWorkSize + 0x30 * params.effectCount + (4 * params.voiceCount) + 0x8F) & ~0x3FL) + ((params.voiceCount << 8) | 0x40);
|
||||
|
||||
if (params.performanceManagerCount > 0) {
|
||||
i64 performanceMetricsBufferSize;
|
||||
i64 performanceMetricsBufferSize{};
|
||||
|
||||
if (revisionInfo.UsesPerformanceMetricDataFormatV2()) {
|
||||
performanceMetricsBufferSize = (params.voiceCount + params.effectCount + totalMixCount + params.sinkCount) + 0x990;
|
||||
|
@ -43,7 +43,7 @@ namespace skyline::service::lm {
|
||||
LogLevel level;
|
||||
u8 verbosity;
|
||||
u32 payloadLength;
|
||||
} data = state.process->GetReference<Data>(request.inputBuf.at(0).address);
|
||||
} &data = state.process->GetReference<Data>(request.inputBuf.at(0).address);
|
||||
|
||||
std::ostringstream logMessage;
|
||||
logMessage << "Guest log:";
|
||||
|
@ -22,7 +22,7 @@ namespace skyline::service::nvdrv::device {
|
||||
void NvHostAsGpu::BindChannel(IoctlData &buffer) {
|
||||
struct Data {
|
||||
u32 fd;
|
||||
} channelInfo = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
} &channelInfo = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
}
|
||||
|
||||
void NvHostAsGpu::AllocSpace(IoctlData &buffer) {
|
||||
@ -100,7 +100,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 pad;
|
||||
u64 pages;
|
||||
} regions[2];
|
||||
} regionInfo = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
} ®ionInfo = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
state.process->WriteMemory(regionInfo, buffer.output.at(0).address);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 raw;
|
||||
} flags;
|
||||
Fence fence;
|
||||
} args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
||||
} &args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
||||
|
||||
auto &hostSyncpoint = state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->hostSyncpoint;
|
||||
|
||||
@ -103,7 +103,7 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 flags;
|
||||
Fence fence;
|
||||
u32 reserved[3];
|
||||
} args = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
} &args = state.process->GetReference<Data>(buffer.input.at(0).address);
|
||||
|
||||
channelFence.UpdateValue(state.os->serviceManager.GetService<nvdrv::INvDrvServices>(Service::nvdrv_INvDrvServices)->hostSyncpoint);
|
||||
args.fence = channelFence;
|
||||
|
@ -83,7 +83,7 @@ namespace skyline::service::nvdrv::device {
|
||||
Fence fence;
|
||||
u32 timeout;
|
||||
EventValue value;
|
||||
} args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
||||
} &args = state.process->GetReference<Data>(buffer.output.at(0).address);
|
||||
|
||||
if (args.fence.id >= constant::MaxHwSyncpointCount) {
|
||||
buffer.status = NvStatus::BadValue;
|
||||
@ -155,11 +155,7 @@ namespace skyline::service::nvdrv::device {
|
||||
}
|
||||
|
||||
void NvHostCtrl::EventSignal(IoctlData &buffer) {
|
||||
struct Data {
|
||||
u16 _pad_;
|
||||
u16 userEventId;
|
||||
};
|
||||
auto userEventId = state.process->GetObject<Data>(buffer.input.at(0).address).userEventId;
|
||||
auto userEventId = static_cast<u16>(state.process->GetObject<u32>(buffer.input.at(0).address));
|
||||
state.logger->Debug("Signalling nvhost event: {}", userEventId);
|
||||
|
||||
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId)) {
|
||||
|
Loading…
Reference in New Issue
Block a user