mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 07:55: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/sm/IUserInterface.cpp
|
||||
${source_DIR}/skyline/services/fatalsrv/IService.cpp
|
||||
${source_DIR}/skyline/services/audout/audout.cpp
|
||||
${source_DIR}/skyline/services/audren/IAudioRendererManager.cpp
|
||||
${source_DIR}/skyline/services/audren/IAudioRenderer.cpp
|
||||
${source_DIR}/skyline/services/audren/voice.cpp
|
||||
${source_DIR}/skyline/services/audren/memoryPool.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioOut.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRendererManager.cpp
|
||||
${source_DIR}/skyline/services/audio/IAudioRenderer/IAudioRenderer.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/apm/apm.cpp
|
||||
${source_DIR}/skyline/services/am/applet.cpp
|
||||
|
@ -13,7 +13,11 @@ namespace skyline::audio {
|
||||
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);
|
||||
audioTracks.push_back(track);
|
||||
|
||||
@ -27,7 +31,7 @@ namespace skyline::audio {
|
||||
|
||||
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
|
||||
i16 *destBuffer = static_cast<i16 *>(audioData);
|
||||
int setIndex = 0;
|
||||
uint setIndex = 0;
|
||||
size_t sampleI16Size = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
|
||||
|
||||
for (auto &track : audioTracks) {
|
||||
|
@ -20,6 +20,11 @@ namespace skyline::audio {
|
||||
public:
|
||||
Audio(const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief The destructor for the audio class
|
||||
*/
|
||||
~Audio();
|
||||
|
||||
/**
|
||||
* @brief Opens a new track that can be used to play sound
|
||||
* @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
|
||||
* @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
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "track.h"
|
||||
|
||||
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)
|
||||
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
|
||||
std::deque<BufferIdentifier> identifierQueue; //!< Queue of all appended buffer identifiers
|
||||
|
||||
int channelCount; //!< The amount channels present in the track
|
||||
int sampleRate; //!< The sample rate of the track
|
||||
const int channelCount; //!< The amount channels present in the track
|
||||
const int sampleRate; //!< The sample rate of the track
|
||||
|
||||
public:
|
||||
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 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.
|
||||
|
@ -1,36 +1,8 @@
|
||||
#include "audout.h"
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include "IAudioOut.h"
|
||||
|
||||
namespace skyline::service::audout {
|
||||
audoutU::audoutU(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audout_u, "audout:u", {
|
||||
{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", {
|
||||
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", {
|
||||
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
|
||||
{0x1, SFUNC(IAudioOut::StartAudioOut)},
|
||||
{0x2, SFUNC(IAudioOut::StopAudioOut)},
|
||||
@ -39,7 +11,7 @@ namespace skyline::service::audout {
|
||||
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
|
||||
{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() {
|
||||
@ -74,7 +46,7 @@ namespace skyline::service::audout {
|
||||
|
||||
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
|
||||
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);
|
||||
}
|
||||
|
@ -1,53 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <audio/resampler.h>
|
||||
#include <audio.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <services/base_service.h>
|
||||
#include <services/serviceman.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
|
||||
namespace skyline::service::audout {
|
||||
namespace constant {
|
||||
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
|
||||
};
|
||||
#include <audio/resampler.h>
|
||||
#include <audio.h>
|
||||
|
||||
namespace skyline::service::audio {
|
||||
/**
|
||||
* @brief audout:u or IAudioOutManager is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
|
||||
*/
|
||||
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)
|
||||
* @brief IAudioOut is a service opened when OpenAudioOut is called by IAudioOutManager (https://switchbrew.org/wiki/Audio_services#IAudioOut)
|
||||
*/
|
||||
class IAudioOut : public BaseService {
|
||||
private:
|
||||
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
|
||||
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
|
||||
|
||||
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 sampleRate; //!< The sample rate of the audio out
|
||||
const int channelCount; //!< The amount of channels in the data sent to the audio out
|
||||
|
||||
public:
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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
|
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 "IAudioRenderer.h"
|
||||
|
||||
namespace skyline::service::audren {
|
||||
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms) : releaseEvent(std::make_shared<type::KEvent>(state)), rendererParams(params), BaseService(state, manager, Service::IAudioRenderer, "IAudioRenderer", {
|
||||
namespace skyline::service::audio::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)},
|
||||
{0x1, SFUNC(IAudioRenderer::GetSampleCount)},
|
||||
{0x2, SFUNC(IAudioRenderer::GetMixBufferCount)},
|
||||
@ -12,11 +13,9 @@ namespace skyline::service::audren {
|
||||
{0x6, SFUNC(IAudioRenderer::Stop)},
|
||||
{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();
|
||||
|
||||
samplesPerBuffer = state.settings->GetInt("audren_buffer_size");
|
||||
memoryPoolCount = rendererParams.effectCount + rendererParams.voiceCount * 4;
|
||||
memoryPools.resize(memoryPoolCount);
|
||||
effects.resize(rendererParams.effectCount);
|
||||
voices.resize(rendererParams.voiceCount, Voice(state));
|
||||
@ -78,7 +77,7 @@ namespace skyline::service::audren {
|
||||
|
||||
UpdateAudio();
|
||||
|
||||
UpdateDataHeader outputHeader {
|
||||
UpdateDataHeader outputHeader{
|
||||
.revision = constant::RevMagic,
|
||||
.behaviorSize = 0xb0,
|
||||
.memoryPoolSize = (rendererParams.effectCount + rendererParams.voiceCount * 4) * static_cast<u32>(sizeof(MemoryPoolOut)),
|
||||
@ -133,7 +132,7 @@ namespace skyline::service::audren {
|
||||
|
||||
void IAudioRenderer::MixFinalBuffer() {
|
||||
int setIndex = 0;
|
||||
sampleBuffer.resize(samplesPerBuffer * audio::constant::ChannelCount);
|
||||
sampleBuffer.resize(samplesPerBuffer * skyline::audio::constant::ChannelCount);
|
||||
|
||||
for (auto &voice : voices) {
|
||||
if (!voice.Playable())
|
||||
@ -150,7 +149,7 @@ namespace skyline::service::audren {
|
||||
if (voiceBufferSize == 0)
|
||||
break;
|
||||
|
||||
pendingSamples -= voiceBufferSize / audio::constant::ChannelCount;
|
||||
pendingSamples -= voiceBufferSize / skyline::audio::constant::ChannelCount;
|
||||
|
||||
for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) {
|
||||
if (setIndex == bufferOffset) {
|
||||
@ -160,8 +159,8 @@ namespace skyline::service::audren {
|
||||
setIndex++;
|
||||
} else {
|
||||
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>(std::numeric_limits<i16>::min()), static_cast<int>(std::numeric_limits<i16>::max())));
|
||||
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())));
|
||||
}
|
||||
|
||||
bufferOffset++;
|
||||
@ -171,11 +170,11 @@ namespace skyline::service::audren {
|
||||
}
|
||||
|
||||
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) {
|
||||
playbackState = audio::AudioOutState::Stopped;
|
||||
playbackState = skyline::audio::AudioOutState::Stopped;
|
||||
}
|
||||
|
||||
void IAudioRenderer::QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <audio.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <services/base_service.h>
|
||||
#include <services/serviceman.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <audio.h>
|
||||
#include "memoryPool.h"
|
||||
#include "effect.h"
|
||||
#include "voice.h"
|
||||
#include "revisionInfo.h"
|
||||
|
||||
namespace skyline::service::audren {
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
namespace constant {
|
||||
constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers
|
||||
}
|
||||
@ -58,18 +58,18 @@ namespace skyline::service::audren {
|
||||
*/
|
||||
class IAudioRenderer : public BaseService {
|
||||
private:
|
||||
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio 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::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<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
|
||||
size_t memoryPoolCount{}; //!< The amount of memory pools the guest may need
|
||||
int samplesPerBuffer{}; //!< The amount of samples each appended buffer should contain
|
||||
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
|
||||
const size_t memoryPoolCount; //!< The amount of memory pools the guest may need
|
||||
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
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::service::audren {
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
/**
|
||||
* @brief This enumerates various states an effect can be in
|
||||
*/
|
@ -1,7 +1,6 @@
|
||||
#include <common.h>
|
||||
#include "memoryPool.h"
|
||||
|
||||
namespace skyline::service::audren {
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
void MemoryPool::ProcessInput(const MemoryPoolIn &input) {
|
||||
if (input.state == MemoryPoolState::RequestAttach)
|
||||
output.state = MemoryPoolState::Attached;
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::service::audren {
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
/**
|
||||
* @brief This enumerates various states a memory pool can be in
|
||||
*/
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::service::audren {
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
namespace constant {
|
||||
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
|
@ -1,8 +1,7 @@
|
||||
#include <common.h>
|
||||
#include "voice.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) {}
|
||||
|
||||
void Voice::ProcessInput(const VoiceIn &input) {
|
||||
@ -23,7 +22,7 @@ namespace skyline::service::audren {
|
||||
return;
|
||||
|
||||
if (input.firstUpdate) {
|
||||
if (input.pcmFormat != audio::PcmFormat::Int16)
|
||||
if (input.pcmFormat != skyline::audio::PcmFormat::Int16)
|
||||
throw exception("Unsupported voice PCM format: {}", input.pcmFormat);
|
||||
|
||||
pcmFormat = input.pcmFormat;
|
||||
@ -48,7 +47,7 @@ namespace skyline::service::audren {
|
||||
return;
|
||||
|
||||
switch (pcmFormat) {
|
||||
case audio::PcmFormat::Int16:
|
||||
case skyline::audio::PcmFormat::Int16:
|
||||
sampleBuffer.resize(currentBuffer.size / sizeof(i16));
|
||||
state.process->ReadMemory(sampleBuffer.data(), currentBuffer.position, currentBuffer.size);
|
||||
break;
|
||||
@ -56,15 +55,15 @@ namespace skyline::service::audren {
|
||||
throw exception("Unsupported voice PCM format: {}", pcmFormat);
|
||||
}
|
||||
|
||||
if (sampleRate != audio::constant::SampleRate)
|
||||
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
|
||||
if (sampleRate != skyline::audio::constant::SampleRate)
|
||||
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();
|
||||
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 (uint i = 0; i < audio::constant::ChannelCount; i++)
|
||||
for (uint i = 0; i < skyline::audio::constant::ChannelCount; i++)
|
||||
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
|
||||
}
|
||||
}
|
||||
@ -72,7 +71,7 @@ namespace skyline::service::audren {
|
||||
std::vector<i16> &Voice::GetBufferData(int maxSamples, int &outOffset, int &outSize) {
|
||||
WaveBuffer ¤tBuffer = waveBuffers.at(bufferIndex);
|
||||
|
||||
if (!acquired || playbackState != audio::AudioOutState::Started) {
|
||||
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
|
||||
outSize = 0;
|
||||
return sampleBuffer;
|
||||
}
|
||||
@ -83,16 +82,16 @@ namespace skyline::service::audren {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (sampleOffset == sampleBuffer.size()) {
|
||||
sampleOffset = 0;
|
||||
|
||||
if (currentBuffer.lastBuffer)
|
||||
playbackState = audio::AudioOutState::Paused;
|
||||
playbackState = skyline::audio::AudioOutState::Paused;
|
||||
|
||||
if (!currentBuffer.looping)
|
||||
SetWaveBufferIndex(bufferIndex + 1);
|
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
#include <array>
|
||||
#include <audio.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
|
||||
*/
|
||||
@ -46,8 +46,8 @@ namespace skyline::service::audren {
|
||||
u32 nodeId; //!< The node ID of the voice
|
||||
u8 firstUpdate; //!< Whether this voice is new
|
||||
u8 acquired; //!< Whether the sample is in use
|
||||
audio::AudioOutState playbackState; //!< The playback state
|
||||
audio::PcmFormat pcmFormat; //!< The sample format
|
||||
skyline::audio::AudioOutState playbackState; //!< The playback state
|
||||
skyline::audio::PcmFormat pcmFormat; //!< The sample format
|
||||
u32 sampleRate; //!< The sample rate
|
||||
u32 priority; //!< The priority for this voice
|
||||
u32 _unk0_;
|
||||
@ -87,7 +87,7 @@ namespace skyline::service::audren {
|
||||
const DeviceState &state; //!< The emulator state object
|
||||
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
|
||||
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 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 sampleRate{}; //!< The sample rate of 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
|
||||
audio::PcmFormat pcmFormat{audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
|
||||
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
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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 "IAudioRenderer/IAudioRenderer.h"
|
||||
#include "IAudioRendererManager.h"
|
||||
|
||||
namespace skyline::service::audren {
|
||||
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::IAudioRendererManager, "IAudioRendererManager", {
|
||||
namespace skyline::service::audio {
|
||||
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audio_IAudioRendererManager, "audio:IAudioRendererManager", {
|
||||
{0x0, SFUNC(IAudioRendererManager::OpenAudioRenderer)},
|
||||
{0x1, SFUNC(IAudioRendererManager::GetAudioRendererWorkBufferSize)}
|
||||
}) {}
|
||||
|
||||
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: {}",
|
||||
ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||
|
||||
manager.RegisterService(std::make_shared<IAudioRenderer>(state, manager, params), session, response);
|
||||
IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
|
||||
|
||||
manager.RegisterService(std::make_shared<IAudioRenderer::IAudioRenderer>(state, manager, params), session, 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);
|
||||
|
||||
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 +
|
||||
totalMixCount * 0x940 +
|
||||
params.voiceCount * 0x3F0 +
|
||||
utils::AlignUp(totalMixCount * 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.effectCount + params.voiceCount * 4) * 0x30 +
|
||||
0x50;
|
||||
|
||||
if (revisionInfo.SplitterSupported()) {
|
||||
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment);
|
||||
|
||||
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, IAudioRenderer::constant::BufferAlignment);
|
||||
if (nodeStateWorkSize < 0)
|
||||
nodeStateWorkSize |= 7;
|
||||
|
||||
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)
|
||||
edgeMatrixWorkSize |= 7;
|
||||
|
@ -1,25 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <audio.h>
|
||||
#include <services/base_service.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 {
|
||||
public:
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
};
|
@ -38,10 +38,10 @@ namespace skyline::service {
|
||||
am_ILibraryAppletCreator,
|
||||
am_IDebugFunctions,
|
||||
am_IAppletCommonFunctions,
|
||||
audout_u,
|
||||
audout_IAudioOut,
|
||||
IAudioRendererManager,
|
||||
IAudioRenderer,
|
||||
audio_IAudioOutManager,
|
||||
audio_IAudioOut,
|
||||
audio_IAudioRendererManager,
|
||||
audio_IAudioRenderer,
|
||||
hid_IHidServer,
|
||||
hid_IAppletResource,
|
||||
timesrv_IStaticService,
|
||||
@ -66,8 +66,8 @@ namespace skyline::service {
|
||||
{"apm", Service::apm},
|
||||
{"appletOE", Service::am_appletOE},
|
||||
{"appletAE", Service::am_appletAE},
|
||||
{"audout:u", Service::audout_u},
|
||||
{"audren:u", Service::IAudioRendererManager},
|
||||
{"audout:u", Service::audio_IAudioOutManager},
|
||||
{"audren:u", Service::audio_IAudioRendererManager},
|
||||
{"hid", Service::hid_IHidServer},
|
||||
{"time:s", Service::timesrv_IStaticService},
|
||||
{"time:a", Service::timesrv_IStaticService},
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include <kernel/types/KProcess.h>
|
||||
#include <services/audren/IAudioRendererManager.h>
|
||||
#include "sm/IUserInterface.h"
|
||||
#include "settings/ISystemSettingsServer.h"
|
||||
#include "apm/apm.h"
|
||||
#include "am/applet.h"
|
||||
#include "am/appletController.h"
|
||||
#include "audout/audout.h"
|
||||
#include "audio/IAudioOutManager.h"
|
||||
#include "audio/IAudioRendererManager.h"
|
||||
#include "fatalsrv/IService.h"
|
||||
#include "hid/IHidServer.h"
|
||||
#include "timesrv/IStaticService.h"
|
||||
@ -41,11 +41,11 @@ namespace skyline::service {
|
||||
case Service::am_appletAE:
|
||||
serviceObj = std::make_shared<am::appletAE>(state, *this);
|
||||
break;
|
||||
case Service::audout_u:
|
||||
serviceObj = std::make_shared<audout::audoutU>(state, *this);
|
||||
case Service::audio_IAudioOutManager:
|
||||
serviceObj = std::make_shared<audio::IAudioOutManager>(state, *this);
|
||||
break;
|
||||
case Service::IAudioRendererManager:
|
||||
serviceObj = std::make_shared<audren::IAudioRendererManager>(state, *this);
|
||||
case Service::audio_IAudioRendererManager:
|
||||
serviceObj = std::make_shared<audio::IAudioRendererManager>(state, *this);
|
||||
break;
|
||||
case Service::hid_IHidServer:
|
||||
serviceObj = std::make_shared<hid::IHidServer>(state, *this);
|
||||
|
Loading…
Reference in New Issue
Block a user