summaryrefslogtreecommitdiff
path: root/src/audio_core/hle/source.cpp
diff options
context:
space:
mode:
authorGravatar James Rowe2018-01-11 19:21:20 -0700
committerGravatar James Rowe2018-01-12 19:11:03 -0700
commitebf9a784a9f7f4148a669dbb39e7cd50df779a14 (patch)
treed585685a1c0a34b903af1d086d62560bf56bb29f /src/audio_core/hle/source.cpp
parentconfig: Default CPU core to Unicorn. (diff)
downloadyuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.gz
yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.xz
yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.zip
Massive removal of unused modules
Diffstat (limited to 'src/audio_core/hle/source.cpp')
-rw-r--r--src/audio_core/hle/source.cpp349
1 files changed, 0 insertions, 349 deletions
diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp
deleted file mode 100644
index c12287700..000000000
--- a/src/audio_core/hle/source.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include "audio_core/codec.h"
8#include "audio_core/hle/common.h"
9#include "audio_core/hle/source.h"
10#include "audio_core/interpolate.h"
11#include "common/assert.h"
12#include "common/logging/log.h"
13#include "core/memory.h"
14
15namespace DSP {
16namespace HLE {
17
18SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config,
19 const s16_le (&adpcm_coeffs)[16]) {
20 ParseConfig(config, adpcm_coeffs);
21
22 if (state.enabled) {
23 GenerateFrame();
24 }
25
26 return GetCurrentStatus();
27}
28
29void Source::MixInto(QuadFrame32& dest, size_t intermediate_mix_id) const {
30 if (!state.enabled)
31 return;
32
33 const std::array<float, 4>& gains = state.gain.at(intermediate_mix_id);
34 for (size_t samplei = 0; samplei < samples_per_frame; samplei++) {
35 // Conversion from stereo (current_frame) to quadraphonic (dest) occurs here.
36 dest[samplei][0] += static_cast<s32>(gains[0] * current_frame[samplei][0]);
37 dest[samplei][1] += static_cast<s32>(gains[1] * current_frame[samplei][1]);
38 dest[samplei][2] += static_cast<s32>(gains[2] * current_frame[samplei][0]);
39 dest[samplei][3] += static_cast<s32>(gains[3] * current_frame[samplei][1]);
40 }
41}
42
43void Source::Reset() {
44 current_frame.fill({});
45 state = {};
46}
47
48void Source::ParseConfig(SourceConfiguration::Configuration& config,
49 const s16_le (&adpcm_coeffs)[16]) {
50 if (!config.dirty_raw) {
51 return;
52 }
53
54 if (config.reset_flag) {
55 config.reset_flag.Assign(0);
56 Reset();
57 LOG_TRACE(Audio_DSP, "source_id=%zu reset", source_id);
58 }
59
60 if (config.partial_reset_flag) {
61 config.partial_reset_flag.Assign(0);
62 state.input_queue = std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder>{};
63 LOG_TRACE(Audio_DSP, "source_id=%zu partial_reset", source_id);
64 }
65
66 if (config.enable_dirty) {
67 config.enable_dirty.Assign(0);
68 state.enabled = config.enable != 0;
69 LOG_TRACE(Audio_DSP, "source_id=%zu enable=%d", source_id, state.enabled);
70 }
71
72 if (config.sync_dirty) {
73 config.sync_dirty.Assign(0);
74 state.sync = config.sync;
75 LOG_TRACE(Audio_DSP, "source_id=%zu sync=%u", source_id, state.sync);
76 }
77
78 if (config.rate_multiplier_dirty) {
79 config.rate_multiplier_dirty.Assign(0);
80 state.rate_multiplier = config.rate_multiplier;
81 LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier);
82
83 if (state.rate_multiplier <= 0) {
84 LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f",
85 source_id, state.rate_multiplier);
86 state.rate_multiplier = 1.0f;
87 // Note: Actual firmware starts producing garbage if this occurs.
88 }
89 }
90
91 if (config.adpcm_coefficients_dirty) {
92 config.adpcm_coefficients_dirty.Assign(0);
93 std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(),
94 state.adpcm_coeffs.begin(),
95 [](const auto& coeff) { return static_cast<s16>(coeff); });
96 LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id);
97 }
98
99 if (config.gain_0_dirty) {
100 config.gain_0_dirty.Assign(0);
101 std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(),
102 [](const auto& coeff) { return static_cast<float>(coeff); });
103 LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id);
104 }
105
106 if (config.gain_1_dirty) {
107 config.gain_1_dirty.Assign(0);
108 std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(),
109 [](const auto& coeff) { return static_cast<float>(coeff); });
110 LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id);
111 }
112
113 if (config.gain_2_dirty) {
114 config.gain_2_dirty.Assign(0);
115 std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(),
116 [](const auto& coeff) { return static_cast<float>(coeff); });
117 LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id);
118 }
119
120 if (config.filters_enabled_dirty) {
121 config.filters_enabled_dirty.Assign(0);
122 state.filters.Enable(config.simple_filter_enabled.ToBool(),
123 config.biquad_filter_enabled.ToBool());
124 LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu", source_id,
125 config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value());
126 }
127
128 if (config.simple_filter_dirty) {
129 config.simple_filter_dirty.Assign(0);
130 state.filters.Configure(config.simple_filter);
131 LOG_TRACE(Audio_DSP, "source_id=%zu simple filter update", source_id);
132 }
133
134 if (config.biquad_filter_dirty) {
135 config.biquad_filter_dirty.Assign(0);
136 state.filters.Configure(config.biquad_filter);
137 LOG_TRACE(Audio_DSP, "source_id=%zu biquad filter update", source_id);
138 }
139
140 if (config.interpolation_dirty) {
141 config.interpolation_dirty.Assign(0);
142 state.interpolation_mode = config.interpolation_mode;
143 LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id,
144 static_cast<size_t>(state.interpolation_mode));
145 }
146
147 if (config.format_dirty || config.embedded_buffer_dirty) {
148 config.format_dirty.Assign(0);
149 state.format = config.format;
150 LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id,
151 static_cast<size_t>(state.format));
152 }
153
154 if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) {
155 config.mono_or_stereo_dirty.Assign(0);
156 state.mono_or_stereo = config.mono_or_stereo;
157 LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id,
158 static_cast<size_t>(state.mono_or_stereo));
159 }
160
161 u32_dsp play_position = {};
162 if (config.play_position_dirty && config.play_position != 0) {
163 config.play_position_dirty.Assign(0);
164 play_position = config.play_position;
165 // play_position applies only to the embedded buffer, and defaults to 0 w/o a dirty bit
166 // This will be the starting sample for the first time the buffer is played.
167 }
168
169 if (config.embedded_buffer_dirty) {
170 config.embedded_buffer_dirty.Assign(0);
171 state.input_queue.emplace(Buffer{
172 config.physical_address,
173 config.length,
174 static_cast<u8>(config.adpcm_ps),
175 {config.adpcm_yn[0], config.adpcm_yn[1]},
176 config.adpcm_dirty.ToBool(),
177 config.is_looping.ToBool(),
178 config.buffer_id,
179 state.mono_or_stereo,
180 state.format,
181 false,
182 play_position,
183 false,
184 });
185 LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu start=%u",
186 config.physical_address, config.length, config.buffer_id,
187 static_cast<u32>(config.play_position));
188 }
189
190 if (config.loop_related_dirty && config.loop_related != 0) {
191 config.loop_related_dirty.Assign(0);
192 LOG_WARNING(Audio_DSP, "Unhandled complex loop with loop_related=0x%08x",
193 static_cast<u32>(config.loop_related));
194 }
195
196 if (config.buffer_queue_dirty) {
197 config.buffer_queue_dirty.Assign(0);
198 for (size_t i = 0; i < 4; i++) {
199 if (config.buffers_dirty & (1 << i)) {
200 const auto& b = config.buffers[i];
201 state.input_queue.emplace(Buffer{
202 b.physical_address,
203 b.length,
204 static_cast<u8>(b.adpcm_ps),
205 {b.adpcm_yn[0], b.adpcm_yn[1]},
206 b.adpcm_dirty != 0,
207 b.is_looping != 0,
208 b.buffer_id,
209 state.mono_or_stereo,
210 state.format,
211 true,
212 {}, // 0 in u32_dsp
213 false,
214 });
215 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i,
216 b.physical_address, b.length, b.buffer_id);
217 }
218 }
219 config.buffers_dirty = 0;
220 }
221
222 if (config.dirty_raw) {
223 LOG_DEBUG(Audio_DSP, "source_id=%zu remaining_dirty=%x", source_id, config.dirty_raw);
224 }
225
226 config.dirty_raw = 0;
227}
228
229void Source::GenerateFrame() {
230 current_frame.fill({});
231
232 if (state.current_buffer.empty() && !DequeueBuffer()) {
233 state.enabled = false;
234 state.buffer_update = true;
235 state.current_buffer_id = 0;
236 return;
237 }
238
239 size_t frame_position = 0;
240
241 state.current_sample_number = state.next_sample_number;
242 while (frame_position < current_frame.size()) {
243 if (state.current_buffer.empty() && !DequeueBuffer()) {
244 break;
245 }
246
247 switch (state.interpolation_mode) {
248 case InterpolationMode::None:
249 AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier,
250 current_frame, frame_position);
251 break;
252 case InterpolationMode::Linear:
253 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier,
254 current_frame, frame_position);
255 break;
256 case InterpolationMode::Polyphase:
257 // TODO(merry): Implement polyphase interpolation
258 LOG_DEBUG(Audio_DSP, "Polyphase interpolation unimplemented; falling back to linear");
259 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier,
260 current_frame, frame_position);
261 break;
262 default:
263 UNIMPLEMENTED();
264 break;
265 }
266 }
267 state.next_sample_number += static_cast<u32>(frame_position);
268
269 state.filters.ProcessFrame(current_frame);
270}
271
272bool Source::DequeueBuffer() {
273 ASSERT_MSG(state.current_buffer.empty(),
274 "Shouldn't dequeue; we still have data in current_buffer");
275
276 if (state.input_queue.empty())
277 return false;
278
279 Buffer buf = state.input_queue.top();
280
281 // if we're in a loop, the current sound keeps playing afterwards, so leave the queue alone
282 if (!buf.is_looping) {
283 state.input_queue.pop();
284 }
285
286 if (buf.adpcm_dirty) {
287 state.adpcm_state.yn1 = buf.adpcm_yn[0];
288 state.adpcm_state.yn2 = buf.adpcm_yn[1];
289 }
290
291 const u8* const memory = Memory::GetPhysicalPointer(buf.physical_address);
292 if (memory) {
293 const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1;
294 switch (buf.format) {
295 case Format::PCM8:
296 state.current_buffer = Codec::DecodePCM8(num_channels, memory, buf.length);
297 break;
298 case Format::PCM16:
299 state.current_buffer = Codec::DecodePCM16(num_channels, memory, buf.length);
300 break;
301 case Format::ADPCM:
302 DEBUG_ASSERT(num_channels == 1);
303 state.current_buffer =
304 Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state);
305 break;
306 default:
307 UNIMPLEMENTED();
308 break;
309 }
310 } else {
311 LOG_WARNING(Audio_DSP,
312 "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X",
313 source_id, buf.buffer_id, buf.length, buf.physical_address);
314 state.current_buffer.clear();
315 return true;
316 }
317
318 // the first playthrough starts at play_position, loops start at the beginning of the buffer
319 state.current_sample_number = (!buf.has_played) ? buf.play_position : 0;
320 state.next_sample_number = state.current_sample_number;
321 state.current_buffer_id = buf.buffer_id;
322 state.buffer_update = buf.from_queue && !buf.has_played;
323
324 buf.has_played = true;
325
326 LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu",
327 source_id, buf.buffer_id, buf.from_queue ? "true" : "false",
328 state.current_buffer.size());
329 return true;
330}
331
332SourceStatus::Status Source::GetCurrentStatus() {
333 SourceStatus::Status ret;
334
335 // Applications depend on the correct emulation of
336 // current_buffer_id_dirty and current_buffer_id to synchronise
337 // audio with video.
338 ret.is_enabled = state.enabled;
339 ret.current_buffer_id_dirty = state.buffer_update ? 1 : 0;
340 state.buffer_update = false;
341 ret.current_buffer_id = state.current_buffer_id;
342 ret.buffer_position = state.current_sample_number;
343 ret.sync = state.sync;
344
345 return ret;
346}
347
348} // namespace HLE
349} // namespace DSP