1 // Copyright 2016 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <vector> 9 #include <boost/serialization/array.hpp> 10 #include <boost/serialization/deque.hpp> 11 #include <boost/serialization/priority_queue.hpp> 12 #include <boost/serialization/vector.hpp> 13 #include <queue> 14 #include "audio_core/audio_types.h" 15 #include "audio_core/codec.h" 16 #include "audio_core/hle/common.h" 17 #include "audio_core/hle/filter.h" 18 #include "audio_core/interpolate.h" 19 #include "common/common_types.h" 20 21 namespace Memory { 22 class MemorySystem; 23 } 24 25 namespace AudioCore::HLE { 26 27 /** 28 * This module performs: 29 * - Buffer management 30 * - Decoding of buffers 31 * - Buffer resampling and interpolation 32 * - Per-source filtering (SimpleFilter, BiquadFilter) 33 * - Per-source gain 34 * - Other per-source processing 35 */ 36 class Source final { 37 public: Source(std::size_t source_id_)38 explicit Source(std::size_t source_id_) : source_id(source_id_) { 39 Reset(); 40 } 41 42 /// Resets internal state. 43 void Reset(); 44 45 /// Sets the memory system to read data from 46 void SetMemory(Memory::MemorySystem& memory); 47 48 /** 49 * This is called once every audio frame. This performs per-source processing every frame. 50 * @param config The new configuration we've got for this Source from the application. 51 * @param adpcm_coeffs ADPCM coefficients to use if config tells us to use them (may contain 52 * invalid values otherwise). 53 * @return The current status of this Source. This is given back to the emulated application via 54 * SharedMemory. 55 */ 56 SourceStatus::Status Tick(SourceConfiguration::Configuration& config, 57 const s16_le (&adpcm_coeffs)[16]); 58 59 /** 60 * Mix this source's output into dest, using the gains for the `intermediate_mix_id`-th 61 * intermediate mixer. 62 * @param dest The QuadFrame32 to mix into. 63 * @param intermediate_mix_id The id of the intermediate mix whose gains we are using. 64 */ 65 void MixInto(QuadFrame32& dest, std::size_t intermediate_mix_id) const; 66 67 private: 68 const std::size_t source_id; 69 Memory::MemorySystem* memory_system; 70 StereoFrame16 current_frame; 71 72 using Format = SourceConfiguration::Configuration::Format; 73 using InterpolationMode = SourceConfiguration::Configuration::InterpolationMode; 74 using MonoOrStereo = SourceConfiguration::Configuration::MonoOrStereo; 75 76 /// Internal representation of a buffer for our buffer queue 77 struct Buffer { 78 PAddr physical_address; 79 u32 length; 80 u8 adpcm_ps; 81 std::array<u16, 2> adpcm_yn; 82 bool adpcm_dirty; 83 bool is_looping; 84 u16 buffer_id; 85 86 MonoOrStereo mono_or_stereo; 87 Format format; 88 89 bool from_queue; 90 u32_dsp play_position; // = 0; 91 bool has_played; // = false; 92 93 private: 94 template <class Archive> serializeBuffer95 void serialize(Archive& ar, const unsigned int) { 96 ar& physical_address; 97 ar& length; 98 ar& adpcm_ps; 99 ar& adpcm_yn; 100 ar& adpcm_dirty; 101 ar& is_looping; 102 ar& buffer_id; 103 ar& mono_or_stereo; 104 ar& format; 105 ar& from_queue; 106 ar& play_position; 107 ar& has_played; 108 } 109 friend class boost::serialization::access; 110 }; 111 112 struct BufferOrder { operatorBufferOrder113 bool operator()(const Buffer& a, const Buffer& b) const { 114 // Lower buffer_id comes first. 115 return a.buffer_id > b.buffer_id; 116 } 117 }; 118 119 struct { 120 121 // State variables 122 123 bool enabled = false; 124 u16 sync = 0; 125 126 // Mixing 127 128 std::array<std::array<float, 4>, 3> gain = {}; 129 130 // Buffer queue 131 132 std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder> input_queue = {}; 133 MonoOrStereo mono_or_stereo = MonoOrStereo::Mono; 134 Format format = Format::ADPCM; 135 136 // Current buffer 137 138 u32 current_sample_number = 0; 139 u32 next_sample_number = 0; 140 PAddr current_buffer_physical_address = 0; 141 AudioInterp::StereoBuffer16 current_buffer = {}; 142 143 // buffer_id state 144 145 bool buffer_update = false; 146 u32 current_buffer_id = 0; 147 148 // Decoding state 149 150 std::array<s16, 16> adpcm_coeffs = {}; 151 Codec::ADPCMState adpcm_state = {}; 152 153 // Resampling state 154 155 float rate_multiplier = 1.0; 156 InterpolationMode interpolation_mode = InterpolationMode::Polyphase; 157 AudioInterp::State interp_state = {}; 158 159 // Filter state 160 161 SourceFilters filters = {}; 162 163 private: 164 template <class Archive> serialize__anon3d9f39400108165 void serialize(Archive& ar, const unsigned int) { 166 ar& enabled; 167 ar& sync; 168 ar& gain; 169 ar& input_queue; 170 ar& mono_or_stereo; 171 ar& format; 172 ar& current_sample_number; 173 ar& next_sample_number; 174 ar& current_buffer_physical_address; 175 ar& current_buffer; 176 ar& buffer_update; 177 ar& current_buffer_id; 178 ar& adpcm_coeffs; 179 ar& rate_multiplier; 180 ar& interpolation_mode; 181 } 182 friend class boost::serialization::access; 183 184 } state; 185 186 // Internal functions 187 188 /// INTERNAL: Update our internal state based on the current config. 189 void ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]); 190 /// INTERNAL: Generate the current audio output for this frame based on our internal state. 191 void GenerateFrame(); 192 /// INTERNAL: Dequeues a buffer and does preprocessing on it (decoding, resampling). Puts it 193 /// into current_buffer. 194 bool DequeueBuffer(); 195 /// INTERNAL: Generates a SourceStatus::Status based on our internal state. 196 SourceStatus::Status GetCurrentStatus(); 197 198 template <class Archive> serialize(Archive & ar,const unsigned int)199 void serialize(Archive& ar, const unsigned int) { 200 ar& state; 201 } 202 friend class boost::serialization::access; 203 }; 204 205 } // namespace AudioCore::HLE 206