summaryrefslogtreecommitdiff
path: root/src/audio_core/hle/source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core/hle/source.cpp')
-rw-r--r--src/audio_core/hle/source.cpp86
1 files changed, 51 insertions, 35 deletions
diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp
index 30552fe26..2bbf7146e 100644
--- a/src/audio_core/hle/source.cpp
+++ b/src/audio_core/hle/source.cpp
@@ -4,21 +4,19 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7
8#include "audio_core/codec.h" 7#include "audio_core/codec.h"
9#include "audio_core/hle/common.h" 8#include "audio_core/hle/common.h"
10#include "audio_core/hle/source.h" 9#include "audio_core/hle/source.h"
11#include "audio_core/interpolate.h" 10#include "audio_core/interpolate.h"
12
13#include "common/assert.h" 11#include "common/assert.h"
14#include "common/logging/log.h" 12#include "common/logging/log.h"
15
16#include "core/memory.h" 13#include "core/memory.h"
17 14
18namespace DSP { 15namespace DSP {
19namespace HLE { 16namespace HLE {
20 17
21SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) { 18SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config,
19 const s16_le (&adpcm_coeffs)[16]) {
22 ParseConfig(config, adpcm_coeffs); 20 ParseConfig(config, adpcm_coeffs);
23 21
24 if (state.enabled) { 22 if (state.enabled) {
@@ -47,7 +45,8 @@ void Source::Reset() {
47 state = {}; 45 state = {};
48} 46}
49 47
50void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) { 48void Source::ParseConfig(SourceConfiguration::Configuration& config,
49 const s16_le (&adpcm_coeffs)[16]) {
51 if (!config.dirty_raw) { 50 if (!config.dirty_raw) {
52 return; 51 return;
53 } 52 }
@@ -82,7 +81,8 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l
82 LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier); 81 LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier);
83 82
84 if (state.rate_multiplier <= 0) { 83 if (state.rate_multiplier <= 0) {
85 LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f", source_id, state.rate_multiplier); 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; 86 state.rate_multiplier = 1.0f;
87 // Note: Actual firmware starts producing garbage if this occurs. 87 // Note: Actual firmware starts producing garbage if this occurs.
88 } 88 }
@@ -90,37 +90,39 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l
90 90
91 if (config.adpcm_coefficients_dirty) { 91 if (config.adpcm_coefficients_dirty) {
92 config.adpcm_coefficients_dirty.Assign(0); 92 config.adpcm_coefficients_dirty.Assign(0);
93 std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(), state.adpcm_coeffs.begin(), 93 std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(),
94 [](const auto& coeff) { return static_cast<s16>(coeff); }); 94 state.adpcm_coeffs.begin(),
95 [](const auto& coeff) { return static_cast<s16>(coeff); });
95 LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id); 96 LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id);
96 } 97 }
97 98
98 if (config.gain_0_dirty) { 99 if (config.gain_0_dirty) {
99 config.gain_0_dirty.Assign(0); 100 config.gain_0_dirty.Assign(0);
100 std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(), 101 std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(),
101 [](const auto& coeff) { return static_cast<float>(coeff); }); 102 [](const auto& coeff) { return static_cast<float>(coeff); });
102 LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id); 103 LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id);
103 } 104 }
104 105
105 if (config.gain_1_dirty) { 106 if (config.gain_1_dirty) {
106 config.gain_1_dirty.Assign(0); 107 config.gain_1_dirty.Assign(0);
107 std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(), 108 std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(),
108 [](const auto& coeff) { return static_cast<float>(coeff); }); 109 [](const auto& coeff) { return static_cast<float>(coeff); });
109 LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id); 110 LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id);
110 } 111 }
111 112
112 if (config.gain_2_dirty) { 113 if (config.gain_2_dirty) {
113 config.gain_2_dirty.Assign(0); 114 config.gain_2_dirty.Assign(0);
114 std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(), 115 std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(),
115 [](const auto& coeff) { return static_cast<float>(coeff); }); 116 [](const auto& coeff) { return static_cast<float>(coeff); });
116 LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id); 117 LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id);
117 } 118 }
118 119
119 if (config.filters_enabled_dirty) { 120 if (config.filters_enabled_dirty) {
120 config.filters_enabled_dirty.Assign(0); 121 config.filters_enabled_dirty.Assign(0);
121 state.filters.Enable(config.simple_filter_enabled.ToBool(), config.biquad_filter_enabled.ToBool()); 122 state.filters.Enable(config.simple_filter_enabled.ToBool(),
122 LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu", 123 config.biquad_filter_enabled.ToBool());
123 source_id, config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value()); 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());
124 } 126 }
125 127
126 if (config.simple_filter_dirty) { 128 if (config.simple_filter_dirty) {
@@ -138,19 +140,22 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l
138 if (config.interpolation_dirty) { 140 if (config.interpolation_dirty) {
139 config.interpolation_dirty.Assign(0); 141 config.interpolation_dirty.Assign(0);
140 state.interpolation_mode = config.interpolation_mode; 142 state.interpolation_mode = config.interpolation_mode;
141 LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id, static_cast<size_t>(state.interpolation_mode)); 143 LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id,
144 static_cast<size_t>(state.interpolation_mode));
142 } 145 }
143 146
144 if (config.format_dirty || config.embedded_buffer_dirty) { 147 if (config.format_dirty || config.embedded_buffer_dirty) {
145 config.format_dirty.Assign(0); 148 config.format_dirty.Assign(0);
146 state.format = config.format; 149 state.format = config.format;
147 LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id, static_cast<size_t>(state.format)); 150 LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id,
151 static_cast<size_t>(state.format));
148 } 152 }
149 153
150 if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) { 154 if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) {
151 config.mono_or_stereo_dirty.Assign(0); 155 config.mono_or_stereo_dirty.Assign(0);
152 state.mono_or_stereo = config.mono_or_stereo; 156 state.mono_or_stereo = config.mono_or_stereo;
153 LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id, static_cast<size_t>(state.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));
154 } 159 }
155 160
156 if (config.embedded_buffer_dirty) { 161 if (config.embedded_buffer_dirty) {
@@ -159,15 +164,16 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l
159 config.physical_address, 164 config.physical_address,
160 config.length, 165 config.length,
161 static_cast<u8>(config.adpcm_ps), 166 static_cast<u8>(config.adpcm_ps),
162 { config.adpcm_yn[0], config.adpcm_yn[1] }, 167 {config.adpcm_yn[0], config.adpcm_yn[1]},
163 config.adpcm_dirty.ToBool(), 168 config.adpcm_dirty.ToBool(),
164 config.is_looping.ToBool(), 169 config.is_looping.ToBool(),
165 config.buffer_id, 170 config.buffer_id,
166 state.mono_or_stereo, 171 state.mono_or_stereo,
167 state.format, 172 state.format,
168 false 173 false,
169 }); 174 });
170 LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu", config.physical_address, config.length, config.buffer_id); 175 LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu",
176 config.physical_address, config.length, config.buffer_id);
171 } 177 }
172 178
173 if (config.buffer_queue_dirty) { 179 if (config.buffer_queue_dirty) {
@@ -179,15 +185,16 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l
179 b.physical_address, 185 b.physical_address,
180 b.length, 186 b.length,
181 static_cast<u8>(b.adpcm_ps), 187 static_cast<u8>(b.adpcm_ps),
182 { b.adpcm_yn[0], b.adpcm_yn[1] }, 188 {b.adpcm_yn[0], b.adpcm_yn[1]},
183 b.adpcm_dirty != 0, 189 b.adpcm_dirty != 0,
184 b.is_looping != 0, 190 b.is_looping != 0,
185 b.buffer_id, 191 b.buffer_id,
186 state.mono_or_stereo, 192 state.mono_or_stereo,
187 state.format, 193 state.format,
188 true 194 true,
189 }); 195 });
190 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i, b.physical_address, b.length, b.buffer_id); 196 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i,
197 b.physical_address, b.length, b.buffer_id);
191 } 198 }
192 } 199 }
193 config.buffers_dirty = 0; 200 config.buffers_dirty = 0;
@@ -218,10 +225,13 @@ void Source::GenerateFrame() {
218 break; 225 break;
219 } 226 }
220 227
221 const size_t size_to_copy = std::min(state.current_buffer.size(), current_frame.size() - frame_position); 228 const size_t size_to_copy =
229 std::min(state.current_buffer.size(), current_frame.size() - frame_position);
222 230
223 std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy, current_frame.begin() + frame_position); 231 std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy,
224 state.current_buffer.erase(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy); 232 current_frame.begin() + frame_position);
233 state.current_buffer.erase(state.current_buffer.begin(),
234 state.current_buffer.begin() + size_to_copy);
225 235
226 frame_position += size_to_copy; 236 frame_position += size_to_copy;
227 state.next_sample_number += static_cast<u32>(size_to_copy); 237 state.next_sample_number += static_cast<u32>(size_to_copy);
@@ -230,9 +240,9 @@ void Source::GenerateFrame() {
230 state.filters.ProcessFrame(current_frame); 240 state.filters.ProcessFrame(current_frame);
231} 241}
232 242
233
234bool Source::DequeueBuffer() { 243bool Source::DequeueBuffer() {
235 ASSERT_MSG(state.current_buffer.empty(), "Shouldn't dequeue; we still have data in current_buffer"); 244 ASSERT_MSG(state.current_buffer.empty(),
245 "Shouldn't dequeue; we still have data in current_buffer");
236 246
237 if (state.input_queue.empty()) 247 if (state.input_queue.empty())
238 return false; 248 return false;
@@ -261,29 +271,34 @@ bool Source::DequeueBuffer() {
261 break; 271 break;
262 case Format::ADPCM: 272 case Format::ADPCM:
263 DEBUG_ASSERT(num_channels == 1); 273 DEBUG_ASSERT(num_channels == 1);
264 state.current_buffer = Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state); 274 state.current_buffer =
275 Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state);
265 break; 276 break;
266 default: 277 default:
267 UNIMPLEMENTED(); 278 UNIMPLEMENTED();
268 break; 279 break;
269 } 280 }
270 } else { 281 } else {
271 LOG_WARNING(Audio_DSP, "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X", 282 LOG_WARNING(Audio_DSP,
272 source_id, buf.buffer_id, buf.length, buf.physical_address); 283 "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X",
284 source_id, buf.buffer_id, buf.length, buf.physical_address);
273 state.current_buffer.clear(); 285 state.current_buffer.clear();
274 return true; 286 return true;
275 } 287 }
276 288
277 switch (state.interpolation_mode) { 289 switch (state.interpolation_mode) {
278 case InterpolationMode::None: 290 case InterpolationMode::None:
279 state.current_buffer = AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier); 291 state.current_buffer =
292 AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier);
280 break; 293 break;
281 case InterpolationMode::Linear: 294 case InterpolationMode::Linear:
282 state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); 295 state.current_buffer =
296 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier);
283 break; 297 break;
284 case InterpolationMode::Polyphase: 298 case InterpolationMode::Polyphase:
285 // TODO(merry): Implement polyphase interpolation 299 // TODO(merry): Implement polyphase interpolation
286 state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); 300 state.current_buffer =
301 AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier);
287 break; 302 break;
288 default: 303 default:
289 UNIMPLEMENTED(); 304 UNIMPLEMENTED();
@@ -296,7 +311,8 @@ bool Source::DequeueBuffer() {
296 state.buffer_update = buf.from_queue; 311 state.buffer_update = buf.from_queue;
297 312
298 LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu", 313 LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu",
299 source_id, buf.buffer_id, buf.from_queue ? "true" : "false", state.current_buffer.size()); 314 source_id, buf.buffer_id, buf.from_queue ? "true" : "false",
315 state.current_buffer.size());
300 return true; 316 return true;
301} 317}
302 318