mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 20:31:48 +01:00
Refactor Audio
This commit refactors a lot of audio by fixing a lot of nitpicks here and there.
This commit is contained in:
parent
af98455ede
commit
4e4ed5aac0
@ -26,14 +26,14 @@ include_directories(${source_DIR}/skyline)
|
|||||||
|
|
||||||
add_library(skyline SHARED
|
add_library(skyline SHARED
|
||||||
${source_DIR}/main.cpp
|
${source_DIR}/main.cpp
|
||||||
${source_DIR}/skyline/audio.cpp
|
|
||||||
${source_DIR}/skyline/audio/track.cpp
|
|
||||||
${source_DIR}/skyline/audio/resampler.cpp
|
|
||||||
${source_DIR}/skyline/common.cpp
|
${source_DIR}/skyline/common.cpp
|
||||||
${source_DIR}/skyline/nce/guest.S
|
${source_DIR}/skyline/nce/guest.S
|
||||||
${source_DIR}/skyline/nce/guest.cpp
|
${source_DIR}/skyline/nce/guest.cpp
|
||||||
${source_DIR}/skyline/nce.cpp
|
${source_DIR}/skyline/nce.cpp
|
||||||
${source_DIR}/skyline/jvm.cpp
|
${source_DIR}/skyline/jvm.cpp
|
||||||
|
${source_DIR}/skyline/audio.cpp
|
||||||
|
${source_DIR}/skyline/audio/track.cpp
|
||||||
|
${source_DIR}/skyline/audio/resampler.cpp
|
||||||
${source_DIR}/skyline/gpu.cpp
|
${source_DIR}/skyline/gpu.cpp
|
||||||
${source_DIR}/skyline/gpu/texture.cpp
|
${source_DIR}/skyline/gpu/texture.cpp
|
||||||
${source_DIR}/skyline/os.cpp
|
${source_DIR}/skyline/os.cpp
|
||||||
|
@ -8,23 +8,23 @@
|
|||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr auto SampleRate = 48000; //!< The sampling rate to use for the oboe audio output
|
constexpr auto SampleRate = 48000; //!< The common sampling rate to use for audio output
|
||||||
constexpr auto ChannelCount = 2; //!< The amount of channels to use for the oboe audio output
|
constexpr auto ChannelCount = 2; //!< The common amount of channels to use for audio output
|
||||||
constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The pcm data format to use for the oboe audio output
|
constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The common PCM data format to use for audio output
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace audio {
|
namespace audio {
|
||||||
/**
|
/**
|
||||||
* @brief The available PCM stream formats
|
* @brief The available PCM stream formats
|
||||||
*/
|
*/
|
||||||
enum class PcmFormat : u8 {
|
enum class AudioFormat : u8 {
|
||||||
Invalid = 0, //!< An invalid PCM format
|
Invalid = 0, //!< An invalid PCM format
|
||||||
Int8 = 1, //!< 8 bit integer PCM
|
Int8 = 1, //!< 8 bit integer PCM
|
||||||
Int16 = 2, //!< 16 bit integer PCM
|
Int16 = 2, //!< 16 bit integer PCM
|
||||||
Int24 = 3, //!< 24 bit integer PCM
|
Int24 = 3, //!< 24 bit integer PCM
|
||||||
Int32 = 4, //!< 32 bit integer PCM
|
Int32 = 4, //!< 32 bit integer PCM
|
||||||
PcmFloat = 5, //!< Floating point PCM
|
Float = 5, //!< Floating point PCM
|
||||||
AdPcm = 6 //!< Adaptive differential PCM
|
ADPCM = 6 //!< Adaptive differential PCM
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,12 +37,12 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stores various information about pushed buffers
|
* @brief This stores information about pushed buffers
|
||||||
*/
|
*/
|
||||||
struct BufferIdentifier {
|
struct BufferIdentifier {
|
||||||
u64 tag; //!< The tag of the buffer
|
u64 tag; //!< The tag of the buffer
|
||||||
u64 finalSample; //!< The final sample this buffer will be played in
|
u64 finalSample; //!< The final sample this buffer will be played in
|
||||||
bool released; //!< Whether the buffer has been released
|
bool released; //!< If the buffer has been released
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ namespace skyline::audio {
|
|||||||
{-58, 4354, 26130, 2338}, {-54, 4199, 26169, 2451}, {-50, 4046, 26202, 2568}, {-46, 3897, 26230, 2688},
|
{-58, 4354, 26130, 2338}, {-54, 4199, 26169, 2451}, {-50, 4046, 26202, 2568}, {-46, 3897, 26230, 2688},
|
||||||
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
|
{-42, 3751, 26253, 2811}, {-38, 3608, 26270, 2936}, {-34, 3467, 26281, 3064}, {-32, 3329, 26287, 3195}}};
|
||||||
|
|
||||||
std::vector<i16> Resampler::ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, int channelCount) {
|
std::vector<i16> Resampler::ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, u8 channelCount) {
|
||||||
auto step = static_cast<uint>(ratio * 0x8000);
|
auto step = static_cast<uint>(ratio * 0x8000);
|
||||||
auto outputSize = static_cast<size_t>(inputBuffer.size() / ratio);
|
auto outputSize = static_cast<size_t>(inputBuffer.size() / ratio);
|
||||||
std::vector<i16> outputBuffer(outputSize);
|
std::vector<i16> outputBuffer(outputSize);
|
||||||
@ -132,7 +132,7 @@ namespace skyline::audio {
|
|||||||
for (auto outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) {
|
for (auto outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) {
|
||||||
auto lutIndex = (fraction >> 8) << 2;
|
auto lutIndex = (fraction >> 8) << 2;
|
||||||
|
|
||||||
for (int channel = 0; channel < channelCount; channel++) {
|
for (u8 channel = 0; channel < channelCount; channel++) {
|
||||||
i32 data = inputBuffer[(inIndex + 0) * channelCount + channel] * lut[lutIndex].a +
|
i32 data = inputBuffer[(inIndex + 0) * channelCount + channel] * lut[lutIndex].a +
|
||||||
inputBuffer[(inIndex + 1) * channelCount + channel] * lut[lutIndex].b +
|
inputBuffer[(inIndex + 1) * channelCount + channel] * lut[lutIndex].b +
|
||||||
inputBuffer[(inIndex + 2) * channelCount + channel] * lut[lutIndex].c +
|
inputBuffer[(inIndex + 2) * channelCount + channel] * lut[lutIndex].c +
|
||||||
|
@ -20,6 +20,6 @@ namespace skyline::audio {
|
|||||||
* @param ratio The conversion ratio needed
|
* @param ratio The conversion ratio needed
|
||||||
* @param channelCount The amount of channels the buffer contains
|
* @param channelCount The amount of channels the buffer contains
|
||||||
*/
|
*/
|
||||||
std::vector<i16> ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, int channelCount);
|
std::vector<i16> ResampleBuffer(const std::vector<i16> &inputBuffer, double ratio, u8 channelCount);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "track.h"
|
#include "track.h"
|
||||||
|
|
||||||
namespace skyline::audio {
|
namespace skyline::audio {
|
||||||
AudioTrack::AudioTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
|
AudioTrack::AudioTrack(const u8 channelCount, const u32 sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
|
||||||
if (sampleRate != constant::SampleRate)
|
if (sampleRate != constant::SampleRate)
|
||||||
throw exception("Unsupported audio sample rate: {}", sampleRate);
|
throw exception("Unsupported audio sample rate: {}", sampleRate);
|
||||||
|
|
||||||
@ -13,13 +13,13 @@ namespace skyline::audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioTrack::Stop() {
|
void AudioTrack::Stop() {
|
||||||
while (!identifierQueue.end()->released);
|
while (!identifiers.end()->released);
|
||||||
playbackState = AudioOutState::Stopped;
|
playbackState = AudioOutState::Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioTrack::ContainsBuffer(u64 tag) {
|
bool AudioTrack::ContainsBuffer(u64 tag) {
|
||||||
// Iterate from front of queue as we don't want released samples
|
// Iterate from front of queue as we don't want released samples
|
||||||
for (auto identifier = identifierQueue.crbegin(); identifier != identifierQueue.crend(); ++identifier) {
|
for (auto identifier = identifiers.crbegin(); identifier != identifiers.crend(); ++identifier) {
|
||||||
if (identifier->released)
|
if (identifier->released)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -33,11 +33,11 @@ namespace skyline::audio {
|
|||||||
std::vector<u64> AudioTrack::GetReleasedBuffers(u32 max) {
|
std::vector<u64> AudioTrack::GetReleasedBuffers(u32 max) {
|
||||||
std::vector<u64> bufferIds;
|
std::vector<u64> bufferIds;
|
||||||
|
|
||||||
for (auto i = 0; i < max; i++) {
|
for (auto index = 0; index < max; index++) {
|
||||||
if (!identifierQueue.back().released)
|
if (!identifiers.back().released)
|
||||||
break;
|
break;
|
||||||
bufferIds.push_back(identifierQueue.back().tag);
|
bufferIds.push_back(identifiers.back().tag);
|
||||||
identifierQueue.pop_back();
|
identifiers.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
return bufferIds;
|
return bufferIds;
|
||||||
@ -64,7 +64,7 @@ namespace skyline::audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioTrack::CheckReleasedBuffers() {
|
void AudioTrack::CheckReleasedBuffers() {
|
||||||
for (auto &identifier : identifierQueue) {
|
for (auto &identifier : identifiers) {
|
||||||
if (identifier.finalSample <= sampleCounter && !identifier.released) {
|
if (identifier.finalSample <= sampleCounter && !identifier.released) {
|
||||||
releaseCallback();
|
releaseCallback();
|
||||||
identifier.released = true;
|
identifier.released = true;
|
||||||
|
@ -16,14 +16,14 @@ namespace skyline::audio {
|
|||||||
class AudioTrack {
|
class AudioTrack {
|
||||||
private:
|
private:
|
||||||
const std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
const std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
|
||||||
std::deque<BufferIdentifier> identifierQueue; //!< Queue of all appended buffer identifiers
|
std::deque<BufferIdentifier> identifiers; //!< Queue of all appended buffer identifiers
|
||||||
|
|
||||||
const int channelCount; //!< The amount channels present in the track
|
const u8 channelCount; //!< The amount channels present in the track
|
||||||
const int sampleRate; //!< The sample rate of the track
|
const u32 sampleRate; //!< The sample rate of the track
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::queue<i16> sampleQueue; //!< Queue of all appended buffer data
|
std::queue<i16> sampleQueue; //!< Queue of all appended buffer data
|
||||||
skyline::Mutex bufferLock; //!< Buffer access lock
|
Mutex bufferLock; //!< This mutex ensures that appending to buffers doesn't overlap
|
||||||
|
|
||||||
AudioOutState playbackState{AudioOutState::Stopped}; //!< The current state of playback
|
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 buffer status
|
||||||
@ -33,7 +33,7 @@ namespace skyline::audio {
|
|||||||
* @param sampleRate The sample rate to use for the track
|
* @param sampleRate The sample rate to use for the track
|
||||||
* @param releaseCallback A callback to call when a buffer has been played
|
* @param releaseCallback A callback to call when a buffer has been played
|
||||||
*/
|
*/
|
||||||
AudioTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
|
AudioTrack(const u8 channelCount, const u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Starts audio playback using data from appended buffers.
|
* @brief Starts audio playback using data from appended buffers.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "IAudioOut.h"
|
#include "IAudioOut.h"
|
||||||
|
|
||||||
namespace skyline::service::audio {
|
namespace skyline::service::audio {
|
||||||
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, const int channelCount, const int sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
|
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, const u8 channelCount, const u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
|
||||||
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
|
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
|
||||||
{0x1, SFUNC(IAudioOut::StartAudioOut)},
|
{0x1, SFUNC(IAudioOut::StartAudioOut)},
|
||||||
{0x2, SFUNC(IAudioOut::StopAudioOut)},
|
{0x2, SFUNC(IAudioOut::StopAudioOut)},
|
||||||
|
@ -20,15 +20,15 @@ namespace skyline::service::audio {
|
|||||||
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
|
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
|
std::vector<i16> tmpSampleBuffer; //!< A temporary buffer used to store sample data in AppendAudioOutBuffer
|
||||||
|
|
||||||
const int sampleRate; //!< The sample rate of the audio out
|
const u32 sampleRate; //!< The sample rate of the audio out
|
||||||
const int channelCount; //!< The amount of channels in the data sent to the audio out
|
const u8 channelCount; //!< The amount of channels in the data sent to the audio out
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @param channelCount The channel count of the audio data the audio out will be fed
|
* @param channelCount The channel count of the audio data the audio out will be fed
|
||||||
* @param sampleRate The sample rate of the audio data the audio out will be fed
|
* @param sampleRate The sample rate of the audio data the audio out will be fed
|
||||||
*/
|
*/
|
||||||
IAudioOut(const DeviceState &state, ServiceManager &manager, const int channelCount, const int sampleRate);
|
IAudioOut(const DeviceState &state, ServiceManager &manager, const u8 channelCount, const u32 sampleRate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes the audio track
|
* @brief Closes the audio track
|
||||||
|
@ -29,7 +29,7 @@ namespace skyline::service::audio {
|
|||||||
response.Push<u32>(sampleRate);
|
response.Push<u32>(sampleRate);
|
||||||
response.Push<u16>(channelCount);
|
response.Push<u16>(channelCount);
|
||||||
response.Push<u16>(0);
|
response.Push<u16>(0);
|
||||||
response.Push(static_cast<u32>(skyline::audio::PcmFormat::Int16));
|
response.Push(static_cast<u32>(skyline::audio::AudioFormat::Int16));
|
||||||
response.Push(static_cast<u32>(skyline::audio::AudioOutState::Stopped));
|
response.Push(static_cast<u32>(skyline::audio::AudioOutState::Stopped));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <kernel/types/KEvent.h>
|
#include <kernel/types/KEvent.h>
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
|
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
|
||||||
|
@ -5,6 +5,11 @@
|
|||||||
#include "voice.h"
|
#include "voice.h"
|
||||||
|
|
||||||
namespace skyline::service::audio::IAudioRenderer {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
|
void Voice::SetWaveBufferIndex(u8 index) {
|
||||||
|
bufferIndex = static_cast<u8>(index & 3);
|
||||||
|
bufferReload = true;
|
||||||
|
}
|
||||||
|
|
||||||
Voice::Voice(const DeviceState &state) : state(state) {}
|
Voice::Voice(const DeviceState &state) : state(state) {}
|
||||||
|
|
||||||
void Voice::ProcessInput(const VoiceIn &input) {
|
void Voice::ProcessInput(const VoiceIn &input) {
|
||||||
@ -25,17 +30,18 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (input.firstUpdate) {
|
if (input.firstUpdate) {
|
||||||
if (input.pcmFormat != skyline::audio::PcmFormat::Int16)
|
if (input.format != skyline::audio::AudioFormat::Int16)
|
||||||
throw exception("Unsupported voice PCM format: {}", input.pcmFormat);
|
throw exception("Unsupported voice PCM format: {}", input.format);
|
||||||
|
|
||||||
pcmFormat = input.pcmFormat;
|
format = input.format;
|
||||||
sampleRate = input.sampleRate;
|
sampleRate = input.sampleRate;
|
||||||
|
|
||||||
if (input.channelCount > 2)
|
if (input.channelCount > 2)
|
||||||
throw exception("Unsupported voice channel count: {}", input.channelCount);
|
throw exception("Unsupported voice channel count: {}", input.channelCount);
|
||||||
|
|
||||||
channelCount = input.channelCount;
|
channelCount = static_cast<u8>(input.channelCount);
|
||||||
SetWaveBufferIndex(input.baseWaveBufferIndex);
|
|
||||||
|
SetWaveBufferIndex(static_cast<u8>(input.baseWaveBufferIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
waveBuffers = input.waveBuffers;
|
waveBuffers = input.waveBuffers;
|
||||||
@ -49,34 +55,36 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
if (currentBuffer.size == 0)
|
if (currentBuffer.size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (pcmFormat) {
|
switch (format) {
|
||||||
case skyline::audio::PcmFormat::Int16:
|
case skyline::audio::AudioFormat::Int16:
|
||||||
sampleBuffer.resize(currentBuffer.size / sizeof(i16));
|
samples.resize(currentBuffer.size / sizeof(i16));
|
||||||
state.process->ReadMemory(sampleBuffer.data(), currentBuffer.address, currentBuffer.size);
|
state.process->ReadMemory(samples.data(), currentBuffer.address, currentBuffer.size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw exception("Unsupported voice PCM format: {}", pcmFormat);
|
throw exception("Unsupported PCM format used by Voice: {}", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleRate != constant::SampleRate)
|
if (sampleRate != constant::SampleRate)
|
||||||
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
|
samples = resampler.ResampleBuffer(samples, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
|
||||||
|
|
||||||
if (channelCount == 1 && constant::ChannelCount != channelCount) {
|
if (channelCount == 1 && constant::ChannelCount != channelCount) {
|
||||||
auto originalSize = sampleBuffer.size();
|
auto originalSize = samples.size();
|
||||||
sampleBuffer.resize((originalSize / channelCount) * constant::ChannelCount);
|
samples.resize((originalSize / channelCount) * constant::ChannelCount);
|
||||||
|
|
||||||
for (auto monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--)
|
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 i = 0; i < constant::ChannelCount; i++)
|
||||||
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
|
samples[--targetIndex] = sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<i16> &Voice::GetBufferData(int maxSamples, int &outOffset, int &outSize) {
|
std::vector<i16> &Voice::GetBufferData(u32 maxSamples, u32 &outOffset, u32 &outSize) {
|
||||||
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
||||||
|
|
||||||
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
|
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
|
||||||
outSize = 0;
|
outSize = 0;
|
||||||
return sampleBuffer;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferReload) {
|
if (bufferReload) {
|
||||||
@ -85,28 +93,23 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outOffset = sampleOffset;
|
outOffset = sampleOffset;
|
||||||
outSize = std::min(maxSamples * constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
|
outSize = std::min(maxSamples * constant::ChannelCount, static_cast<u32>(samples.size() - sampleOffset));
|
||||||
|
|
||||||
output.playedSamplesCount += outSize / constant::ChannelCount;
|
output.playedSamplesCount += outSize / constant::ChannelCount;
|
||||||
sampleOffset += outSize;
|
sampleOffset += outSize;
|
||||||
|
|
||||||
if (sampleOffset == sampleBuffer.size()) {
|
if (sampleOffset == samples.size()) {
|
||||||
sampleOffset = 0;
|
sampleOffset = 0;
|
||||||
|
|
||||||
if (currentBuffer.lastBuffer)
|
if (currentBuffer.lastBuffer)
|
||||||
playbackState = skyline::audio::AudioOutState::Paused;
|
playbackState = skyline::audio::AudioOutState::Paused;
|
||||||
|
|
||||||
if (!currentBuffer.looping)
|
if (!currentBuffer.looping)
|
||||||
SetWaveBufferIndex(bufferIndex + 1);
|
SetWaveBufferIndex(static_cast<u8>(bufferIndex + 1));
|
||||||
|
|
||||||
output.playedWaveBuffersCount++;
|
output.playedWaveBuffersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sampleBuffer;
|
return samples;
|
||||||
}
|
|
||||||
|
|
||||||
void Voice::SetWaveBufferIndex(uint index) {
|
|
||||||
bufferIndex = index & 3;
|
|
||||||
bufferReload = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
u8 firstUpdate; //!< Whether this voice is new
|
u8 firstUpdate; //!< Whether this voice is new
|
||||||
u8 acquired; //!< Whether the sample is in use
|
u8 acquired; //!< Whether the sample is in use
|
||||||
skyline::audio::AudioOutState playbackState; //!< The playback state
|
skyline::audio::AudioOutState playbackState; //!< The playback state
|
||||||
skyline::audio::PcmFormat pcmFormat; //!< The sample format
|
skyline::audio::AudioFormat format; //!< The sample format
|
||||||
u32 sampleRate; //!< The sample rate
|
u32 sampleRate; //!< The sample rate
|
||||||
u32 priority; //!< The priority for this voice
|
u32 priority; //!< The priority for this voice
|
||||||
u32 _unk0_;
|
u32 _unk0_;
|
||||||
@ -89,20 +89,20 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
private:
|
private:
|
||||||
const DeviceState &state; //!< The emulator state object
|
const DeviceState &state; //!< The emulator state object
|
||||||
std::array<WaveBuffer, 4> waveBuffers; //!< An array containing the state of all four wave buffers
|
std::array<WaveBuffer, 4> waveBuffers; //!< An array containing the state of all four wave buffers
|
||||||
std::vector<i16> sampleBuffer; //!< A buffer containing processed sample data
|
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
|
skyline::audio::Resampler resampler; //!< The resampler object used for changing the sample rate of a stream
|
||||||
|
|
||||||
bool acquired{false}; //!< If the voice is in use
|
bool acquired{false}; //!< If the voice is in use
|
||||||
bool bufferReload{true}; //!< If the buffer needs to be updated
|
bool bufferReload{true}; //!< If the buffer needs to be updated
|
||||||
uint bufferIndex{}; //!< The index of the wave buffer currently in use
|
u8 bufferIndex{}; //!< The index of the wave buffer currently in use
|
||||||
int sampleOffset{}; //!< The offset in the sample data of the current wave buffer
|
u32 sampleOffset{}; //!< The offset in the sample data of the current wave buffer
|
||||||
int sampleRate{}; //!< The sample rate of the sample data
|
u32 sampleRate{}; //!< The sample rate of the sample data
|
||||||
int channelCount{}; //!< The amount of channels in 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::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The playback state of the voice
|
||||||
skyline::audio::PcmFormat pcmFormat{skyline::audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
|
skyline::audio::AudioFormat format{skyline::audio::AudioFormat::Invalid}; //!< The format used for guest audio data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the sample buffer with data from the current wave buffer and processes it
|
* @brief This updates the sample buffer with data from the current wave buffer and processes it
|
||||||
*/
|
*/
|
||||||
void UpdateBuffers();
|
void UpdateBuffers();
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
* @brief Sets the current wave buffer index to use
|
* @brief Sets the current wave buffer index to use
|
||||||
* @param index The index to use
|
* @param index The index to use
|
||||||
*/
|
*/
|
||||||
void SetWaveBufferIndex(uint index);
|
void SetWaveBufferIndex(u8 index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VoiceOut output{}; //!< The current output state
|
VoiceOut output{}; //!< The current output state
|
||||||
@ -119,20 +119,20 @@ namespace skyline::service::audio::IAudioRenderer {
|
|||||||
Voice(const DeviceState &state);
|
Voice(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads the input voice data from the guest and sets internal data based off it
|
* @brief This reads the input voice data from the guest and sets internal data based off it
|
||||||
* @param input The input data struct from guest
|
* @param input The input data struct from guest
|
||||||
*/
|
*/
|
||||||
void ProcessInput(const VoiceIn &input);
|
void ProcessInput(const VoiceIn &input);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Obtains the voices audio sample data, updating it if required
|
* @brief This obtains the voices audio sample data, updating it if required
|
||||||
* @param maxSamples The maximum amount of samples the output buffer should contain
|
* @param maxSamples The maximum amount of samples the output buffer should contain
|
||||||
* @return A vector of I16 PCM sample data
|
* @return A vector of I16 PCM sample data
|
||||||
*/
|
*/
|
||||||
std::vector<i16> &GetBufferData(int maxSamples, int &outOffset, int &outSize);
|
std::vector<i16> &GetBufferData(u32 maxSamples, u32 &outOffset, u32 &outSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether the voice is currently playable
|
* @return If the voice is currently playable
|
||||||
*/
|
*/
|
||||||
inline bool Playable() {
|
inline bool Playable() {
|
||||||
return acquired && playbackState == skyline::audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
|
return acquired && playbackState == skyline::audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
|
||||||
|
@ -12,7 +12,7 @@ namespace skyline::service::audio {
|
|||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
void IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
|
IAudioRenderer::AudioRendererParameters params = request.Pop<IAudioRenderer::AudioRendererParameters>();
|
||||||
|
|
||||||
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}", IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}", IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||||
|
|
||||||
@ -20,34 +20,34 @@ namespace skyline::service::audio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IAudioRendererManager::GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRendererManager::GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
|
IAudioRenderer::AudioRendererParameters params = request.Pop<IAudioRenderer::AudioRendererParameters>();
|
||||||
|
|
||||||
IAudioRenderer::RevisionInfo revisionInfo{};
|
IAudioRenderer::RevisionInfo revisionInfo{};
|
||||||
revisionInfo.SetUserRevision(params.revision);
|
revisionInfo.SetUserRevision(params.revision);
|
||||||
|
|
||||||
u32 totalMixCount = params.subMixCount + 1;
|
u32 totalMixCount = params.subMixCount + 1;
|
||||||
|
|
||||||
i64 size = utils::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
|
i64 size = util::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
|
||||||
params.subMixCount * 0x400 +
|
params.subMixCount * 0x400 +
|
||||||
totalMixCount * 0x940 +
|
totalMixCount * 0x940 +
|
||||||
params.voiceCount * 0x3F0 +
|
params.voiceCount * 0x3F0 +
|
||||||
utils::AlignUp(totalMixCount * 8, 16) +
|
util::AlignUp(totalMixCount * 8, 16) +
|
||||||
utils::AlignUp(params.voiceCount * 8, 16) +
|
util::AlignUp(params.voiceCount * 8, 16) +
|
||||||
utils::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()) {
|
if (revisionInfo.SplitterSupported()) {
|
||||||
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment);
|
i32 nodeStateWorkSize = util::AlignUp(totalMixCount, constant::BufferAlignment);
|
||||||
if (nodeStateWorkSize < 0)
|
if (nodeStateWorkSize < 0)
|
||||||
nodeStateWorkSize |= 7;
|
nodeStateWorkSize |= 7;
|
||||||
|
|
||||||
nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8);
|
nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8);
|
||||||
|
|
||||||
i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment);
|
i32 edgeMatrixWorkSize = util::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment);
|
||||||
if (edgeMatrixWorkSize < 0)
|
if (edgeMatrixWorkSize < 0)
|
||||||
edgeMatrixWorkSize |= 7;
|
edgeMatrixWorkSize |= 7;
|
||||||
|
|
||||||
edgeMatrixWorkSize /= 8;
|
edgeMatrixWorkSize /= 8;
|
||||||
size += utils::AlignUp(edgeMatrixWorkSize + nodeStateWorkSize, 16);
|
size += util::AlignUp(edgeMatrixWorkSize + nodeStateWorkSize, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 splitterWorkSize = 0;
|
i64 splitterWorkSize = 0;
|
||||||
@ -56,8 +56,9 @@ namespace skyline::service::audio {
|
|||||||
splitterWorkSize += params.splitterDestinationDataCount * 0xE0 + params.splitterCount * 0x20;
|
splitterWorkSize += params.splitterDestinationDataCount * 0xE0 + params.splitterCount * 0x20;
|
||||||
|
|
||||||
if (revisionInfo.SplitterBugFixed())
|
if (revisionInfo.SplitterBugFixed())
|
||||||
splitterWorkSize += utils::AlignUp(4 * params.splitterDestinationDataCount, 16);
|
splitterWorkSize += util::AlignUp(4 * params.splitterDestinationDataCount, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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) {
|
if (params.performanceManagerCount > 0) {
|
||||||
@ -78,7 +79,7 @@ namespace skyline::service::audio {
|
|||||||
size += 0x1807E;
|
size += 0x1807E;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = utils::AlignUp(size, 0x1000);
|
size = util::AlignUp(size, 0x1000);
|
||||||
|
|
||||||
state.logger->Debug("IAudioRendererManager: Work buffer size: 0x{:X}", size);
|
state.logger->Debug("IAudioRendererManager: Work buffer size: 0x{:X}", size);
|
||||||
response.Push<i64>(size);
|
response.Push<i64>(size);
|
||||||
|
Loading…
Reference in New Issue
Block a user