citra/src/audio_core/hle/source.h

158 lines
4.5 KiB
C++
Raw Normal View History

2016-04-25 08:54:57 +01:00
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <vector>
#include <queue>
2017-12-20 18:44:32 +00:00
#include "audio_core/audio_types.h"
2016-04-25 08:54:57 +01:00
#include "audio_core/codec.h"
#include "audio_core/hle/common.h"
#include "audio_core/hle/filter.h"
#include "audio_core/interpolate.h"
#include "common/common_types.h"
namespace Memory {
class MemorySystem;
}
2017-12-20 18:44:32 +00:00
namespace AudioCore {
2016-04-25 08:54:57 +01:00
namespace HLE {
/**
* This module performs:
* - Buffer management
* - Decoding of buffers
* - Buffer resampling and interpolation
* - Per-source filtering (SimpleFilter, BiquadFilter)
* - Per-source gain
* - Other per-source processing
*/
class Source final {
public:
explicit Source(std::size_t source_id_) : source_id(source_id_) {
2016-04-25 08:54:57 +01:00
Reset();
}
/// Resets internal state.
void Reset();
/// Sets the memory system to read data from
void SetMemory(Memory::MemorySystem& memory);
2016-04-25 08:54:57 +01:00
/**
* This is called once every audio frame. This performs per-source processing every frame.
* @param config The new configuration we've got for this Source from the application.
* @param adpcm_coeffs ADPCM coefficients to use if config tells us to use them (may contain
* invalid values otherwise).
* @return The current status of this Source. This is given back to the emulated application via
* SharedMemory.
2016-04-25 08:54:57 +01:00
*/
SourceStatus::Status Tick(SourceConfiguration::Configuration& config,
const s16_le (&adpcm_coeffs)[16]);
2016-04-25 08:54:57 +01:00
/**
* Mix this source's output into dest, using the gains for the `intermediate_mix_id`-th
* intermediate mixer.
2016-04-25 08:54:57 +01:00
* @param dest The QuadFrame32 to mix into.
* @param intermediate_mix_id The id of the intermediate mix whose gains we are using.
*/
void MixInto(QuadFrame32& dest, std::size_t intermediate_mix_id) const;
2016-04-25 08:54:57 +01:00
private:
const std::size_t source_id;
Memory::MemorySystem* memory_system;
2016-04-25 08:54:57 +01:00
StereoFrame16 current_frame;
using Format = SourceConfiguration::Configuration::Format;
using InterpolationMode = SourceConfiguration::Configuration::InterpolationMode;
using MonoOrStereo = SourceConfiguration::Configuration::MonoOrStereo;
/// Internal representation of a buffer for our buffer queue
struct Buffer {
PAddr physical_address;
u32 length;
u8 adpcm_ps;
std::array<u16, 2> adpcm_yn;
bool adpcm_dirty;
bool is_looping;
u16 buffer_id;
MonoOrStereo mono_or_stereo;
Format format;
bool from_queue;
u32_dsp play_position; // = 0;
bool has_played; // = false;
2016-04-25 08:54:57 +01:00
};
struct BufferOrder {
bool operator()(const Buffer& a, const Buffer& b) const {
2016-04-25 08:54:57 +01:00
// Lower buffer_id comes first.
return a.buffer_id > b.buffer_id;
}
};
struct {
// State variables
bool enabled = false;
u16 sync = 0;
// Mixing
std::array<std::array<float, 4>, 3> gain = {};
// Buffer queue
std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder> input_queue;
MonoOrStereo mono_or_stereo = MonoOrStereo::Mono;
Format format = Format::ADPCM;
// Current buffer
u32 current_sample_number = 0;
u32 next_sample_number = 0;
AudioInterp::StereoBuffer16 current_buffer;
2016-04-25 08:54:57 +01:00
// buffer_id state
bool buffer_update = false;
u32 current_buffer_id = 0;
// Decoding state
std::array<s16, 16> adpcm_coeffs = {};
Codec::ADPCMState adpcm_state = {};
// Resampling state
float rate_multiplier = 1.0;
InterpolationMode interpolation_mode = InterpolationMode::Polyphase;
AudioInterp::State interp_state = {};
// Filter state
SourceFilters filters;
} state;
// Internal functions
/// INTERNAL: Update our internal state based on the current config.
void ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]);
/// INTERNAL: Generate the current audio output for this frame based on our internal state.
void GenerateFrame();
/// INTERNAL: Dequeues a buffer and does preprocessing on it (decoding, resampling). Puts it
/// into current_buffer.
2016-04-25 08:54:57 +01:00
bool DequeueBuffer();
/// INTERNAL: Generates a SourceStatus::Status based on our internal state.
SourceStatus::Status GetCurrentStatus();
};
} // namespace HLE
2017-12-20 18:44:32 +00:00
} // namespace AudioCore