mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 16:35:29 +03:00
Refactor audio backend and services
Use the new service naming convention. Move both audout and audren into one directory. Close the audio stream upon emulator exit.
This commit is contained in:
parent
2e0ac9bdd5
commit
52d47120a8
@ -52,11 +52,12 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/services/serviceman.cpp
|
${source_DIR}/skyline/services/serviceman.cpp
|
||||||
${source_DIR}/skyline/services/sm/IUserInterface.cpp
|
${source_DIR}/skyline/services/sm/IUserInterface.cpp
|
||||||
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
||||||
${source_DIR}/skyline/services/audout/audout.cpp
|
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
|
||||||
${source_DIR}/skyline/services/audren/IAudioRendererManager.cpp
|
${source_DIR}/skyline/services/audio/IAudioOut.cpp
|
||||||
${source_DIR}/skyline/services/audren/IAudioRenderer.cpp
|
${source_DIR}/skyline/services/audio/IAudioRendererManager.cpp
|
||||||
${source_DIR}/skyline/services/audren/voice.cpp
|
${source_DIR}/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp
|
||||||
${source_DIR}/skyline/services/audren/memoryPool.cpp
|
${source_DIR}/skyline/services/audio/IAudioRenderer/voice.cpp
|
||||||
|
${source_DIR}/skyline/services/audio/IAudioRenderer/memoryPool.cpp
|
||||||
${source_DIR}/skyline/services/settings/ISystemSettingsServer.cpp
|
${source_DIR}/skyline/services/settings/ISystemSettingsServer.cpp
|
||||||
${source_DIR}/skyline/services/apm/apm.cpp
|
${source_DIR}/skyline/services/apm/apm.cpp
|
||||||
${source_DIR}/skyline/services/am/applet.cpp
|
${source_DIR}/skyline/services/am/applet.cpp
|
||||||
|
@ -13,7 +13,11 @@ namespace skyline::audio {
|
|||||||
outputStream->requestStart();
|
outputStream->requestStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AudioTrack> Audio::OpenTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback) {
|
Audio::~Audio() {
|
||||||
|
outputStream->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<AudioTrack> Audio::OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback) {
|
||||||
std::shared_ptr<AudioTrack> track = std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback);
|
std::shared_ptr<AudioTrack> track = std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback);
|
||||||
audioTracks.push_back(track);
|
audioTracks.push_back(track);
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ namespace skyline::audio {
|
|||||||
|
|
||||||
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
||||||
i16 *destBuffer = static_cast<i16 *>(audioData);
|
i16 *destBuffer = static_cast<i16 *>(audioData);
|
||||||
int setIndex = 0;
|
uint setIndex = 0;
|
||||||
size_t sampleI16Size = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
size_t sampleI16Size = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
||||||
|
|
||||||
for (auto &track : audioTracks) {
|
for (auto &track : audioTracks) {
|
||||||
|
@ -20,6 +20,11 @@ namespace skyline::audio {
|
|||||||
public:
|
public:
|
||||||
Audio(const DeviceState &state);
|
Audio(const DeviceState &state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The destructor for the audio class
|
||||||
|
*/
|
||||||
|
~Audio();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens a new track that can be used to play sound
|
* @brief Opens a new track that can be used to play sound
|
||||||
* @param channelCount The amount channels that are present in the track
|
* @param channelCount The amount channels that are present in the track
|
||||||
@ -27,7 +32,7 @@ namespace skyline::audio {
|
|||||||
* @param releaseCallback The callback to call when a buffer has been released
|
* @param releaseCallback The callback to call when a buffer has been released
|
||||||
* @return A shared pointer to a new AudioTrack object
|
* @return A shared pointer to a new AudioTrack object
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<AudioTrack> OpenTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback);
|
std::shared_ptr<AudioTrack> OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes a track and frees its data
|
* @brief Closes a track and frees its data
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "track.h"
|
#include "track.h"
|
||||||
|
|
||||||
namespace skyline::audio {
|
namespace skyline::audio {
|
||||||
AudioTrack::AudioTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
|
AudioTrack::AudioTrack(const int channelCount, const int 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);
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ namespace skyline::audio {
|
|||||||
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> identifierQueue; //!< Queue of all appended buffer identifiers
|
||||||
|
|
||||||
int channelCount; //!< The amount channels present in the track
|
const int channelCount; //!< The amount channels present in the track
|
||||||
int sampleRate; //!< The sample rate of the track
|
const int 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
|
||||||
@ -30,7 +30,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(int channelCount, int sampleRate, const std::function<void()> &releaseCallback);
|
AudioTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Starts audio playback using data from appended buffers.
|
* @brief Starts audio playback using data from appended buffers.
|
||||||
|
@ -1,36 +1,8 @@
|
|||||||
#include "audout.h"
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include "IAudioOut.h"
|
||||||
|
|
||||||
namespace skyline::service::audout {
|
namespace skyline::service::audio {
|
||||||
audoutU::audoutU(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audout_u, "audout:u", {
|
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", {
|
||||||
{0x0, SFUNC(audoutU::ListAudioOuts)},
|
|
||||||
{0x1, SFUNC(audoutU::OpenAudioOut)}
|
|
||||||
}) {}
|
|
||||||
|
|
||||||
void audoutU::ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
||||||
state.process->WriteMemory(reinterpret_cast<void *>(const_cast<char *>(constant::DefaultAudioOutName.data())),
|
|
||||||
request.outputBuf.at(0).address, constant::DefaultAudioOutName.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void audoutU::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>();
|
|
||||||
|
|
||||||
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
|
|
||||||
|
|
||||||
sampleRate = sampleRate ? sampleRate : audio::constant::SampleRate;
|
|
||||||
channelCount = channelCount ? channelCount : static_cast<u16>(audio::constant::ChannelCount);
|
|
||||||
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
|
|
||||||
|
|
||||||
response.Push<u32>(sampleRate);
|
|
||||||
response.Push<u16>(channelCount);
|
|
||||||
response.Push<u16>(0);
|
|
||||||
response.Push(static_cast<u32>(audio::PcmFormat::Int16));
|
|
||||||
response.Push(static_cast<u32>(audio::AudioOutState::Stopped));
|
|
||||||
}
|
|
||||||
|
|
||||||
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, int channelCount, int sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audout_IAudioOut, "audout: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)},
|
||||||
@ -39,7 +11,7 @@ namespace skyline::service::audout {
|
|||||||
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
|
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
|
||||||
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
|
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
|
||||||
}) {
|
}) {
|
||||||
track = state.audio->OpenTrack(channelCount, audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
|
track = state.audio->OpenTrack(channelCount, skyline::audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
IAudioOut::~IAudioOut() {
|
IAudioOut::~IAudioOut() {
|
||||||
@ -74,7 +46,7 @@ namespace skyline::service::audout {
|
|||||||
|
|
||||||
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
|
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
|
||||||
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
|
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
|
||||||
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
|
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
|
||||||
track->AppendBuffer(tmpSampleBuffer, tag);
|
track->AppendBuffer(tmpSampleBuffer, tag);
|
||||||
}
|
}
|
||||||
|
|
@ -1,53 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <audio/resampler.h>
|
#include <kernel/types/KEvent.h>
|
||||||
#include <audio.h>
|
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
#include <kernel/types/KEvent.h>
|
#include <audio/resampler.h>
|
||||||
|
#include <audio.h>
|
||||||
namespace skyline::service::audout {
|
|
||||||
namespace constant {
|
|
||||||
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
|
|
||||||
};
|
|
||||||
|
|
||||||
|
namespace skyline::service::audio {
|
||||||
/**
|
/**
|
||||||
* @brief audout:u or IAudioOutManager is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
|
* @brief IAudioOut is a service opened when OpenAudioOut is called by IAudioOutManager (https://switchbrew.org/wiki/Audio_services#IAudioOut)
|
||||||
*/
|
|
||||||
class audoutU : public BaseService {
|
|
||||||
public:
|
|
||||||
audoutU(const DeviceState &state, ServiceManager &manager);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
|
|
||||||
*/
|
|
||||||
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
|
|
||||||
*/
|
|
||||||
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief IAudioOut is a service opened when OpenAudioOut is called by audout (https://switchbrew.org/wiki/Audio_services#IAudioOut)
|
|
||||||
*/
|
*/
|
||||||
class IAudioOut : public BaseService {
|
class IAudioOut : public BaseService {
|
||||||
private:
|
private:
|
||||||
audio::Resampler resampler; //!< The audio resampler object used to resample audio
|
skyline::audio::Resampler resampler; //!< The audio resampler object used to resample audio
|
||||||
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio out
|
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::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
|
||||||
|
|
||||||
int sampleRate; //!< The sample rate of the audio out
|
const int sampleRate; //!< The sample rate of the audio out
|
||||||
int channelCount; //!< The amount of channels in the data sent to the audio out
|
const int 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, int channelCount, int sampleRate);
|
IAudioOut(const DeviceState &state, ServiceManager &manager, const int channelCount, const int sampleRate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes the audio track
|
* @brief Closes the audio track
|
33
app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp
Normal file
33
app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include "IAudioOutManager.h"
|
||||||
|
#include "IAudioOut.h"
|
||||||
|
|
||||||
|
namespace skyline::service::audio {
|
||||||
|
IAudioOutManager::IAudioOutManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audio_IAudioOutManager, "audio:IAudioOutManager", {
|
||||||
|
{0x0, SFUNC(IAudioOutManager::ListAudioOuts)},
|
||||||
|
{0x1, SFUNC(IAudioOutManager::OpenAudioOut)}
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
void IAudioOutManager::ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
state.process->WriteMemory(reinterpret_cast<void *>(const_cast<char *>(constant::DefaultAudioOutName.data())),
|
||||||
|
request.outputBuf.at(0).address, constant::DefaultAudioOutName.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
|
||||||
|
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
|
||||||
|
|
||||||
|
sampleRate = sampleRate ? sampleRate : skyline::audio::constant::SampleRate;
|
||||||
|
channelCount = channelCount ? channelCount : static_cast<u16>(skyline::audio::constant::ChannelCount);
|
||||||
|
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
|
||||||
|
|
||||||
|
response.Push<u32>(sampleRate);
|
||||||
|
response.Push<u16>(channelCount);
|
||||||
|
response.Push<u16>(0);
|
||||||
|
response.Push(static_cast<u32>(skyline::audio::PcmFormat::Int16));
|
||||||
|
response.Push(static_cast<u32>(skyline::audio::AudioOutState::Stopped));
|
||||||
|
}
|
||||||
|
}
|
29
app/src/main/cpp/skyline/services/audio/IAudioOutManager.h
Normal file
29
app/src/main/cpp/skyline/services/audio/IAudioOutManager.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/types/KEvent.h>
|
||||||
|
#include <services/base_service.h>
|
||||||
|
#include <services/serviceman.h>
|
||||||
|
|
||||||
|
namespace skyline::service::audio {
|
||||||
|
namespace constant {
|
||||||
|
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
|
||||||
|
*/
|
||||||
|
class IAudioOutManager : public BaseService {
|
||||||
|
public:
|
||||||
|
IAudioOutManager(const DeviceState &state, ServiceManager &manager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
|
||||||
|
*/
|
||||||
|
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
|
||||||
|
*/
|
||||||
|
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
};
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
#include "IAudioRenderer.h"
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include "IAudioRenderer.h"
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms) : releaseEvent(std::make_shared<type::KEvent>(state)), rendererParams(params), BaseService(state, manager, Service::IAudioRenderer, "IAudioRenderer", {
|
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms)
|
||||||
|
: releaseEvent(std::make_shared<type::KEvent>(state)), rendererParams(params), memoryPoolCount(params.effectCount + params.voiceCount * 4), samplesPerBuffer(state.settings->GetInt("audren_buffer_size")), BaseService(state, manager, Service::audio_IAudioRenderer, "audio:IAudioRenderer", {
|
||||||
{0x0, SFUNC(IAudioRenderer::GetSampleRate)},
|
{0x0, SFUNC(IAudioRenderer::GetSampleRate)},
|
||||||
{0x1, SFUNC(IAudioRenderer::GetSampleCount)},
|
{0x1, SFUNC(IAudioRenderer::GetSampleCount)},
|
||||||
{0x2, SFUNC(IAudioRenderer::GetMixBufferCount)},
|
{0x2, SFUNC(IAudioRenderer::GetMixBufferCount)},
|
||||||
@ -12,11 +13,9 @@ namespace skyline::service::audren {
|
|||||||
{0x6, SFUNC(IAudioRenderer::Stop)},
|
{0x6, SFUNC(IAudioRenderer::Stop)},
|
||||||
{0x7, SFUNC(IAudioRenderer::QuerySystemEvent)},
|
{0x7, SFUNC(IAudioRenderer::QuerySystemEvent)},
|
||||||
}) {
|
}) {
|
||||||
track = state.audio->OpenTrack(audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
|
track = state.audio->OpenTrack(skyline::audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
|
||||||
track->Start();
|
track->Start();
|
||||||
|
|
||||||
samplesPerBuffer = state.settings->GetInt("audren_buffer_size");
|
|
||||||
memoryPoolCount = rendererParams.effectCount + rendererParams.voiceCount * 4;
|
|
||||||
memoryPools.resize(memoryPoolCount);
|
memoryPools.resize(memoryPoolCount);
|
||||||
effects.resize(rendererParams.effectCount);
|
effects.resize(rendererParams.effectCount);
|
||||||
voices.resize(rendererParams.voiceCount, Voice(state));
|
voices.resize(rendererParams.voiceCount, Voice(state));
|
||||||
@ -78,7 +77,7 @@ namespace skyline::service::audren {
|
|||||||
|
|
||||||
UpdateAudio();
|
UpdateAudio();
|
||||||
|
|
||||||
UpdateDataHeader outputHeader {
|
UpdateDataHeader outputHeader{
|
||||||
.revision = constant::RevMagic,
|
.revision = constant::RevMagic,
|
||||||
.behaviorSize = 0xb0,
|
.behaviorSize = 0xb0,
|
||||||
.memoryPoolSize = (rendererParams.effectCount + rendererParams.voiceCount * 4) * static_cast<u32>(sizeof(MemoryPoolOut)),
|
.memoryPoolSize = (rendererParams.effectCount + rendererParams.voiceCount * 4) * static_cast<u32>(sizeof(MemoryPoolOut)),
|
||||||
@ -133,7 +132,7 @@ namespace skyline::service::audren {
|
|||||||
|
|
||||||
void IAudioRenderer::MixFinalBuffer() {
|
void IAudioRenderer::MixFinalBuffer() {
|
||||||
int setIndex = 0;
|
int setIndex = 0;
|
||||||
sampleBuffer.resize(samplesPerBuffer * audio::constant::ChannelCount);
|
sampleBuffer.resize(samplesPerBuffer * skyline::audio::constant::ChannelCount);
|
||||||
|
|
||||||
for (auto &voice : voices) {
|
for (auto &voice : voices) {
|
||||||
if (!voice.Playable())
|
if (!voice.Playable())
|
||||||
@ -150,7 +149,7 @@ namespace skyline::service::audren {
|
|||||||
if (voiceBufferSize == 0)
|
if (voiceBufferSize == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pendingSamples -= voiceBufferSize / audio::constant::ChannelCount;
|
pendingSamples -= voiceBufferSize / skyline::audio::constant::ChannelCount;
|
||||||
|
|
||||||
for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) {
|
for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) {
|
||||||
if (setIndex == bufferOffset) {
|
if (setIndex == bufferOffset) {
|
||||||
@ -160,8 +159,8 @@ namespace skyline::service::audren {
|
|||||||
setIndex++;
|
setIndex++;
|
||||||
} else {
|
} else {
|
||||||
sampleBuffer[bufferOffset] += static_cast<i16>(std::clamp(static_cast<int>(sampleBuffer[voiceSamples[i]]) +
|
sampleBuffer[bufferOffset] += static_cast<i16>(std::clamp(static_cast<int>(sampleBuffer[voiceSamples[i]]) +
|
||||||
static_cast<int>(static_cast<float>(voiceSamples[i]) * voice.volume),
|
static_cast<int>(static_cast<float>(voiceSamples[i]) * voice.volume),
|
||||||
static_cast<int>(std::numeric_limits<i16>::min()), static_cast<int>(std::numeric_limits<i16>::max())));
|
static_cast<int>(std::numeric_limits<i16>::min()), static_cast<int>(std::numeric_limits<i16>::max())));
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferOffset++;
|
bufferOffset++;
|
||||||
@ -171,11 +170,11 @@ namespace skyline::service::audren {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IAudioRenderer::Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRenderer::Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
playbackState = audio::AudioOutState::Started;
|
playbackState = skyline::audio::AudioOutState::Started;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAudioRenderer::Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRenderer::Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
playbackState = audio::AudioOutState::Stopped;
|
playbackState = skyline::audio::AudioOutState::Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAudioRenderer::QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRenderer::QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <audio.h>
|
#include <kernel/types/KEvent.h>
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
#include <kernel/types/KEvent.h>
|
#include <audio.h>
|
||||||
#include "memoryPool.h"
|
#include "memoryPool.h"
|
||||||
#include "effect.h"
|
#include "effect.h"
|
||||||
#include "voice.h"
|
#include "voice.h"
|
||||||
#include "revisionInfo.h"
|
#include "revisionInfo.h"
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers
|
constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers
|
||||||
}
|
}
|
||||||
@ -58,18 +58,18 @@ namespace skyline::service::audren {
|
|||||||
*/
|
*/
|
||||||
class IAudioRenderer : public BaseService {
|
class IAudioRenderer : public BaseService {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio renderer
|
|
||||||
AudioRendererParams rendererParams; //!< The parameters to use for the renderer
|
AudioRendererParams rendererParams; //!< The parameters to use for the renderer
|
||||||
|
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> 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<MemoryPool> memoryPools; //!< An vector of all memory pools that the guest may need
|
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<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<Voice> voices; //!< An vector of all voices that the guest may need
|
||||||
std::vector<i16> sampleBuffer; //!< The final output data that is appended to the stream
|
std::vector<i16> sampleBuffer; //!< The final output data that is appended to the stream
|
||||||
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
|
|
||||||
|
|
||||||
audio::AudioOutState playbackState{audio::AudioOutState::Stopped}; //!< The current state of playback
|
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
|
||||||
size_t memoryPoolCount{}; //!< The amount of memory pools the guest may need
|
const size_t memoryPoolCount; //!< The amount of memory pools the guest may need
|
||||||
int samplesPerBuffer{}; //!< The amount of samples each appended buffer should contain
|
const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Obtains new sample data from voices and mixes it together into the sample buffer
|
* @brief Obtains new sample data from voices and mixes it together into the sample buffer
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
/**
|
/**
|
||||||
* @brief This enumerates various states an effect can be in
|
* @brief This enumerates various states an effect can be in
|
||||||
*/
|
*/
|
@ -1,7 +1,6 @@
|
|||||||
#include <common.h>
|
|
||||||
#include "memoryPool.h"
|
#include "memoryPool.h"
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
void MemoryPool::ProcessInput(const MemoryPoolIn &input) {
|
void MemoryPool::ProcessInput(const MemoryPoolIn &input) {
|
||||||
if (input.state == MemoryPoolState::RequestAttach)
|
if (input.state == MemoryPoolState::RequestAttach)
|
||||||
output.state = MemoryPoolState::Attached;
|
output.state = MemoryPoolState::Attached;
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
/**
|
/**
|
||||||
* @brief This enumerates various states a memory pool can be in
|
* @brief This enumerates various states a memory pool can be in
|
||||||
*/
|
*/
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
|
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
|
||||||
constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic
|
constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic
|
@ -1,8 +1,7 @@
|
|||||||
#include <common.h>
|
|
||||||
#include "voice.h"
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include "voice.h"
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
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) {
|
||||||
@ -23,7 +22,7 @@ namespace skyline::service::audren {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (input.firstUpdate) {
|
if (input.firstUpdate) {
|
||||||
if (input.pcmFormat != audio::PcmFormat::Int16)
|
if (input.pcmFormat != skyline::audio::PcmFormat::Int16)
|
||||||
throw exception("Unsupported voice PCM format: {}", input.pcmFormat);
|
throw exception("Unsupported voice PCM format: {}", input.pcmFormat);
|
||||||
|
|
||||||
pcmFormat = input.pcmFormat;
|
pcmFormat = input.pcmFormat;
|
||||||
@ -48,7 +47,7 @@ namespace skyline::service::audren {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
switch (pcmFormat) {
|
switch (pcmFormat) {
|
||||||
case audio::PcmFormat::Int16:
|
case skyline::audio::PcmFormat::Int16:
|
||||||
sampleBuffer.resize(currentBuffer.size / sizeof(i16));
|
sampleBuffer.resize(currentBuffer.size / sizeof(i16));
|
||||||
state.process->ReadMemory(sampleBuffer.data(), currentBuffer.position, currentBuffer.size);
|
state.process->ReadMemory(sampleBuffer.data(), currentBuffer.position, currentBuffer.size);
|
||||||
break;
|
break;
|
||||||
@ -56,15 +55,15 @@ namespace skyline::service::audren {
|
|||||||
throw exception("Unsupported voice PCM format: {}", pcmFormat);
|
throw exception("Unsupported voice PCM format: {}", pcmFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleRate != audio::constant::SampleRate)
|
if (sampleRate != skyline::audio::constant::SampleRate)
|
||||||
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
|
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
|
||||||
|
|
||||||
if (channelCount == 1 && audio::constant::ChannelCount != channelCount) {
|
if (channelCount == 1 && skyline::audio::constant::ChannelCount != channelCount) {
|
||||||
size_t originalSize = sampleBuffer.size();
|
size_t originalSize = sampleBuffer.size();
|
||||||
sampleBuffer.resize((originalSize / channelCount) * audio::constant::ChannelCount);
|
sampleBuffer.resize((originalSize / channelCount) * skyline::audio::constant::ChannelCount);
|
||||||
|
|
||||||
for (size_t monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--)
|
for (size_t monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--)
|
||||||
for (uint i = 0; i < audio::constant::ChannelCount; i++)
|
for (uint i = 0; i < skyline::audio::constant::ChannelCount; i++)
|
||||||
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
|
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,7 +71,7 @@ namespace skyline::service::audren {
|
|||||||
std::vector<i16> &Voice::GetBufferData(int maxSamples, int &outOffset, int &outSize) {
|
std::vector<i16> &Voice::GetBufferData(int maxSamples, int &outOffset, int &outSize) {
|
||||||
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
||||||
|
|
||||||
if (!acquired || playbackState != audio::AudioOutState::Started) {
|
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
|
||||||
outSize = 0;
|
outSize = 0;
|
||||||
return sampleBuffer;
|
return sampleBuffer;
|
||||||
}
|
}
|
||||||
@ -83,16 +82,16 @@ namespace skyline::service::audren {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outOffset = sampleOffset;
|
outOffset = sampleOffset;
|
||||||
outSize = std::min(maxSamples * audio::constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
|
outSize = std::min(maxSamples * skyline::audio::constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
|
||||||
|
|
||||||
output.playedSamplesCount += outSize / audio::constant::ChannelCount;
|
output.playedSamplesCount += outSize / skyline::audio::constant::ChannelCount;
|
||||||
sampleOffset += outSize;
|
sampleOffset += outSize;
|
||||||
|
|
||||||
if (sampleOffset == sampleBuffer.size()) {
|
if (sampleOffset == sampleBuffer.size()) {
|
||||||
sampleOffset = 0;
|
sampleOffset = 0;
|
||||||
|
|
||||||
if (currentBuffer.lastBuffer)
|
if (currentBuffer.lastBuffer)
|
||||||
playbackState = audio::AudioOutState::Paused;
|
playbackState = skyline::audio::AudioOutState::Paused;
|
||||||
|
|
||||||
if (!currentBuffer.looping)
|
if (!currentBuffer.looping)
|
||||||
SetWaveBufferIndex(bufferIndex + 1);
|
SetWaveBufferIndex(bufferIndex + 1);
|
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <common.h>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <audio.h>
|
|
||||||
#include <audio/resampler.h>
|
#include <audio/resampler.h>
|
||||||
|
#include <audio.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio::IAudioRenderer {
|
||||||
/**
|
/**
|
||||||
* @brief This stores data for configuring a biquadratic filter
|
* @brief This stores data for configuring a biquadratic filter
|
||||||
*/
|
*/
|
||||||
@ -46,8 +46,8 @@ namespace skyline::service::audren {
|
|||||||
u32 nodeId; //!< The node ID of the voice
|
u32 nodeId; //!< The node ID of the voice
|
||||||
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
|
||||||
audio::AudioOutState playbackState; //!< The playback state
|
skyline::audio::AudioOutState playbackState; //!< The playback state
|
||||||
audio::PcmFormat pcmFormat; //!< The sample format
|
skyline::audio::PcmFormat pcmFormat; //!< 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_;
|
||||||
@ -87,7 +87,7 @@ namespace skyline::service::audren {
|
|||||||
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> sampleBuffer; //!< A buffer containing processed sample data
|
||||||
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
|
||||||
@ -95,8 +95,8 @@ namespace skyline::service::audren {
|
|||||||
int sampleOffset{}; //!< The offset in the sample data of the current wave buffer
|
int sampleOffset{}; //!< The offset in the sample data of the current wave buffer
|
||||||
int sampleRate{}; //!< The sample rate of the sample data
|
int sampleRate{}; //!< The sample rate of the sample data
|
||||||
int channelCount{}; //!< The amount of channels in the sample data
|
int channelCount{}; //!< The amount of channels in the sample data
|
||||||
audio::AudioOutState playbackState{audio::AudioOutState::Stopped}; //!< The playback state of the voice
|
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The playback state of the voice
|
||||||
audio::PcmFormat pcmFormat{audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
|
skyline::audio::PcmFormat pcmFormat{skyline::audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the sample buffer with data from the current wave buffer and processes it
|
* @brief Updates the sample buffer with data from the current wave buffer and processes it
|
||||||
@ -132,7 +132,7 @@ namespace skyline::service::audren {
|
|||||||
* @return Whether the voice is currently playable
|
* @return Whether the voice is currently playable
|
||||||
*/
|
*/
|
||||||
inline bool Playable() {
|
inline bool Playable() {
|
||||||
return acquired && playbackState == audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
|
return acquired && playbackState == skyline::audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,52 +1,49 @@
|
|||||||
#include "IAudioRenderer.h"
|
|
||||||
#include "IAudioRendererManager.h"
|
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
|
#include "IAudioRenderer/IAudioRenderer.h"
|
||||||
|
#include "IAudioRendererManager.h"
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio {
|
||||||
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::IAudioRendererManager, "IAudioRendererManager", {
|
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audio_IAudioRendererManager, "audio:IAudioRendererManager", {
|
||||||
{0x0, SFUNC(IAudioRendererManager::OpenAudioRenderer)},
|
{0x0, SFUNC(IAudioRendererManager::OpenAudioRenderer)},
|
||||||
{0x1, SFUNC(IAudioRendererManager::GetAudioRendererWorkBufferSize)}
|
{0x1, SFUNC(IAudioRendererManager::GetAudioRendererWorkBufferSize)}
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
void IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
AudioRendererParams params = request.Pop<AudioRendererParams>();
|
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
|
||||||
|
|
||||||
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}",
|
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}",
|
||||||
ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||||
|
|
||||||
manager.RegisterService(std::make_shared<IAudioRenderer>(state, manager, params), session, response);
|
|
||||||
|
|
||||||
|
manager.RegisterService(std::make_shared<IAudioRenderer::IAudioRenderer>(state, manager, params), session, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IAudioRendererManager::GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAudioRendererManager::GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
AudioRendererParams params = request.Pop<AudioRendererParams>();
|
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
|
||||||
|
|
||||||
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 = utils::AlignUp(params.mixBufferCount * 4, IAudioRenderer::constant::BufferAlignment) +
|
||||||
params.subMixCount * 0x400 +
|
params.subMixCount * 0x400 +
|
||||||
totalMixCount * 0x940 +
|
totalMixCount * 0x940 +
|
||||||
params.voiceCount * 0x3F0 +
|
params.voiceCount * 0x3F0 +
|
||||||
utils::AlignUp(totalMixCount * 8, 16) +
|
utils::AlignUp(totalMixCount * 8, 16) +
|
||||||
utils::AlignUp(params.voiceCount * 8, 16) +
|
utils::AlignUp(params.voiceCount * 8, 16) +
|
||||||
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) +
|
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), IAudioRenderer::constant::BufferAlignment) +
|
||||||
(params.sinkCount + params.subMixCount) * 0x2C0 +
|
(params.sinkCount + params.subMixCount) * 0x2C0 +
|
||||||
(params.effectCount + params.voiceCount * 4) * 0x30 +
|
(params.effectCount + params.voiceCount * 4) * 0x30 +
|
||||||
0x50;
|
0x50;
|
||||||
|
|
||||||
if (revisionInfo.SplitterSupported()) {
|
if (revisionInfo.SplitterSupported()) {
|
||||||
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment);
|
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, IAudioRenderer::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 = utils::AlignUp(totalMixCount * totalMixCount, IAudioRenderer::constant::BufferAlignment);
|
||||||
|
|
||||||
if (edgeMatrixWorkSize < 0)
|
if (edgeMatrixWorkSize < 0)
|
||||||
edgeMatrixWorkSize |= 7;
|
edgeMatrixWorkSize |= 7;
|
||||||
|
|
@ -1,25 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <audio.h>
|
|
||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
#include <kernel/types/KEvent.h>
|
|
||||||
|
|
||||||
namespace skyline::service::audren {
|
namespace skyline::service::audio {
|
||||||
/**
|
/**
|
||||||
* @brief audren:u or IAudioRendererManager is used to manage audio renderer outputs (https://switchbrew.org/wiki/Audio_services#audren:u)
|
* @brief IAudioRendererManager or audren:u is used to manage audio renderer outputs (https://switchbrew.org/wiki/Audio_services#audren:u)
|
||||||
*/
|
*/
|
||||||
class IAudioRendererManager : public BaseService {
|
class IAudioRendererManager : public BaseService {
|
||||||
public:
|
public:
|
||||||
IAudioRendererManager(const DeviceState &state, ServiceManager &manager);
|
IAudioRendererManager(const DeviceState &state, ServiceManager &manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new audrenU::IAudioRenderer object and returns a handle to it
|
* @brief Creates a new IAudioRenderer object and returns a handle to it
|
||||||
*/
|
*/
|
||||||
void OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
void OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Calculates the size of the buffer the guest needs to allocate for audren
|
* @brief Calculates the size of the buffer the guest needs to allocate for IAudioRendererManager
|
||||||
*/
|
*/
|
||||||
void GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
void GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
};
|
};
|
@ -38,10 +38,10 @@ namespace skyline::service {
|
|||||||
am_ILibraryAppletCreator,
|
am_ILibraryAppletCreator,
|
||||||
am_IDebugFunctions,
|
am_IDebugFunctions,
|
||||||
am_IAppletCommonFunctions,
|
am_IAppletCommonFunctions,
|
||||||
audout_u,
|
audio_IAudioOutManager,
|
||||||
audout_IAudioOut,
|
audio_IAudioOut,
|
||||||
IAudioRendererManager,
|
audio_IAudioRendererManager,
|
||||||
IAudioRenderer,
|
audio_IAudioRenderer,
|
||||||
hid_IHidServer,
|
hid_IHidServer,
|
||||||
hid_IAppletResource,
|
hid_IAppletResource,
|
||||||
timesrv_IStaticService,
|
timesrv_IStaticService,
|
||||||
@ -66,8 +66,8 @@ namespace skyline::service {
|
|||||||
{"apm", Service::apm},
|
{"apm", Service::apm},
|
||||||
{"appletOE", Service::am_appletOE},
|
{"appletOE", Service::am_appletOE},
|
||||||
{"appletAE", Service::am_appletAE},
|
{"appletAE", Service::am_appletAE},
|
||||||
{"audout:u", Service::audout_u},
|
{"audout:u", Service::audio_IAudioOutManager},
|
||||||
{"audren:u", Service::IAudioRendererManager},
|
{"audren:u", Service::audio_IAudioRendererManager},
|
||||||
{"hid", Service::hid_IHidServer},
|
{"hid", Service::hid_IHidServer},
|
||||||
{"time:s", Service::timesrv_IStaticService},
|
{"time:s", Service::timesrv_IStaticService},
|
||||||
{"time:a", Service::timesrv_IStaticService},
|
{"time:a", Service::timesrv_IStaticService},
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <services/audren/IAudioRendererManager.h>
|
|
||||||
#include "sm/IUserInterface.h"
|
#include "sm/IUserInterface.h"
|
||||||
#include "settings/ISystemSettingsServer.h"
|
#include "settings/ISystemSettingsServer.h"
|
||||||
#include "apm/apm.h"
|
#include "apm/apm.h"
|
||||||
#include "am/applet.h"
|
#include "am/applet.h"
|
||||||
#include "am/appletController.h"
|
#include "am/appletController.h"
|
||||||
#include "audout/audout.h"
|
#include "audio/IAudioOutManager.h"
|
||||||
|
#include "audio/IAudioRendererManager.h"
|
||||||
#include "fatalsrv/IService.h"
|
#include "fatalsrv/IService.h"
|
||||||
#include "hid/IHidServer.h"
|
#include "hid/IHidServer.h"
|
||||||
#include "timesrv/IStaticService.h"
|
#include "timesrv/IStaticService.h"
|
||||||
@ -41,11 +41,11 @@ namespace skyline::service {
|
|||||||
case Service::am_appletAE:
|
case Service::am_appletAE:
|
||||||
serviceObj = std::make_shared<am::appletAE>(state, *this);
|
serviceObj = std::make_shared<am::appletAE>(state, *this);
|
||||||
break;
|
break;
|
||||||
case Service::audout_u:
|
case Service::audio_IAudioOutManager:
|
||||||
serviceObj = std::make_shared<audout::audoutU>(state, *this);
|
serviceObj = std::make_shared<audio::IAudioOutManager>(state, *this);
|
||||||
break;
|
break;
|
||||||
case Service::IAudioRendererManager:
|
case Service::audio_IAudioRendererManager:
|
||||||
serviceObj = std::make_shared<audren::IAudioRendererManager>(state, *this);
|
serviceObj = std::make_shared<audio::IAudioRendererManager>(state, *this);
|
||||||
break;
|
break;
|
||||||
case Service::hid_IHidServer:
|
case Service::hid_IHidServer:
|
||||||
serviceObj = std::make_shared<hid::IHidServer>(state, *this);
|
serviceObj = std::make_shared<hid::IHidServer>(state, *this);
|
||||||
|
Loading…
Reference in New Issue
Block a user