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