skyline/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.h
◱ PixelyIon c76ef3730b Move to MPL-2.0
We earlier moved to LGPLv3.0 or Later. This was a mistake as what we wanted was being able to link to proprietary libraries but LGPL is the opposite and it allows linking proprietary libraries to libskyline instead. After further consideration, we've moved to MPL-2.0, it allows linking to proprietary libraries and is a standardized license as compared to adding an exception to GPL.
2020-04-23 22:26:27 +05:30

142 lines
5.8 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <array>
#include <audio/resampler.h>
#include <audio.h>
#include <common.h>
namespace skyline::service::audio::IAudioRenderer {
/**
* @brief This stores data for configuring a biquadratic filter
*/
struct BiquadFilter {
u8 enable; //!< Whether to enable the filter
u8 _pad0_;
u16 b0; //!< The b0 constant
u16 b1; //!< The b1 constant
u16 b2; //!< The b2 constant
u16 a1; //!< The a1 constant
u16 a2; //!< The a2 constant
};
static_assert(sizeof(BiquadFilter) == 0xc);
/**
* @brief This stores information of a wave buffer of samples
*/
struct WaveBuffer {
u64 address; //!< The address of the wave buffer in guest memory
u64 size; //!< The size of the wave buffer
u32 firstSampleOffset; //!< The offset of the first sample in the buffer
u32 lastSampleOffset; //!< The offset of the last sample in the buffer
u8 looping; //!< Whether to loop the buffer
u8 lastBuffer; //!< Whether this is the last populated buffer
u16 _unk0_;
u32 _unk1_;
u64 adpcmLoopContextPosition; //!< The position of the ADPCM loop context data
u64 adpcmLoopContextSize; //!< The size of the ADPCM loop context data
u64 _unk2_;
};
static_assert(sizeof(WaveBuffer) == 0x38);
/**
* @brief This is in input containing the configuration of a voice
*/
struct VoiceIn {
u32 slot; //!< The slot of the voice
u32 nodeId; //!< The node ID of the voice
u8 firstUpdate; //!< Whether this voice is new
u8 acquired; //!< Whether the sample is in use
skyline::audio::AudioOutState playbackState; //!< The playback state
skyline::audio::AudioFormat format; //!< The sample format
u32 sampleRate; //!< The sample rate
u32 priority; //!< The priority for this voice
u32 _unk0_;
u32 channelCount; //!< The amount of channels the wave buffers contain
float pitch; //!< The pitch to play wave data at
float volume; //!< The volume to play wave data at
std::array<BiquadFilter, 2> biquadFilters; //!< Biquadratic filter configurations
u32 appendedWaveBuffersCount; //!< The amount of buffers appended
u32 baseWaveBufferIndex; //!< The start index of the buffer to use
u32 _unk1_;
u64 adpcmCoeffsPosition; //!< The ADPCM coefficient position in wave data
u64 adpcmCoeffsSize; //!< The size of the ADPCM coefficient configuration data
u32 destination; //!< The voice destination address
u32 _pad0_;
std::array<WaveBuffer, 4> waveBuffers; //!< The wave buffers for the voice
std::array<u32, 6> voiceChannelResourceIds; //!< A list of IDs corresponding to each channel
u32 _pad1_[6];
};
static_assert(sizeof(VoiceIn) == 0x170);
/**
* @brief This is returned to inform the guest of the state of a voice
*/
struct VoiceOut {
u64 playedSamplesCount; //!< The amount of samples played
u32 playedWaveBuffersCount; //!< The amount of wave buffers fully played
u32 voiceDropsCount; //!< The amount of time audio frames have been dropped due to the rendering time limit
};
static_assert(sizeof(VoiceOut) == 0x10);
/**
* @brief The Voice class manages an audio voice
*/
class Voice {
private:
const DeviceState &state; //!< The emulator state object
std::array<WaveBuffer, 4> waveBuffers; //!< An array containing the state of all four wave buffers
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
bool acquired{false}; //!< If the voice is in use
bool bufferReload{true}; //!< If the buffer needs to be updated
u8 bufferIndex{}; //!< The index of the wave buffer currently in use
u32 sampleOffset{}; //!< The offset in the sample data of the current wave buffer
u32 sampleRate{}; //!< The sample rate of the sample data
u8 channelCount{}; //!< The amount of channels in the sample data
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The playback state of the voice
skyline::audio::AudioFormat format{skyline::audio::AudioFormat::Invalid}; //!< The format used for guest audio data
/**
* @brief This updates the sample buffer with data from the current wave buffer and processes it
*/
void UpdateBuffers();
/**
* @brief Sets the current wave buffer index to use
* @param index The index to use
*/
void SetWaveBufferIndex(u8 index);
public:
VoiceOut output{}; //!< The current output state
float volume{}; //!< The volume of the voice
Voice(const DeviceState &state);
/**
* @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
*/
void ProcessInput(const VoiceIn &input);
/**
* @brief This obtains the voices audio sample data, updating it if required
* @param maxSamples The maximum amount of samples the output buffer should contain
* @return A vector of I16 PCM sample data
*/
std::vector<i16> &GetBufferData(u32 maxSamples, u32 &outOffset, u32 &outSize);
/**
* @return If the voice is currently playable
*/
inline bool Playable() {
return acquired && playbackState == skyline::audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
}
};
}