diff options
| author | 2017-10-09 23:56:20 -0400 | |
|---|---|---|
| committer | 2017-10-09 23:56:20 -0400 | |
| commit | b1d5db1cf60344b6b081c9d03cb6ccc3264326cd (patch) | |
| tree | fde377c4ba3c0f92c032e6f5ec8627aae37270ef /src/audio_core | |
| parent | loader: Various improvements for NSO/NRO loaders. (diff) | |
| parent | Merge pull request #2996 from MerryMage/split-travis (diff) | |
| download | yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.tar.gz yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.tar.xz yuzu-b1d5db1cf60344b6b081c9d03cb6ccc3264326cd.zip | |
Merge remote-tracking branch 'upstream/master' into nx
# Conflicts:
# src/core/CMakeLists.txt
# src/core/arm/dynarmic/arm_dynarmic.cpp
# src/core/arm/dyncom/arm_dyncom.cpp
# src/core/hle/kernel/process.cpp
# src/core/hle/kernel/thread.cpp
# src/core/hle/kernel/thread.h
# src/core/hle/kernel/vm_manager.cpp
# src/core/loader/3dsx.cpp
# src/core/loader/elf.cpp
# src/core/loader/ncch.cpp
# src/core/memory.cpp
# src/core/memory.h
# src/core/memory_setup.h
Diffstat (limited to 'src/audio_core')
| -rw-r--r-- | src/audio_core/codec.cpp | 4 | ||||
| -rw-r--r-- | src/audio_core/codec.h | 4 | ||||
| -rw-r--r-- | src/audio_core/hle/source.cpp | 49 | ||||
| -rw-r--r-- | src/audio_core/hle/source.h | 2 | ||||
| -rw-r--r-- | src/audio_core/interpolate.cpp | 86 | ||||
| -rw-r--r-- | src/audio_core/interpolate.h | 31 |
6 files changed, 82 insertions, 94 deletions
diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp index 7a3bd7eb3..6fba9fdae 100644 --- a/src/audio_core/codec.cpp +++ b/src/audio_core/codec.cpp | |||
| @@ -117,7 +117,9 @@ StereoBuffer16 DecodePCM16(const unsigned num_channels, const u8* const data, | |||
| 117 | ret[i].fill(sample); | 117 | ret[i].fill(sample); |
| 118 | } | 118 | } |
| 119 | } else { | 119 | } else { |
| 120 | std::memcpy(ret.data(), data, sample_count * 2 * sizeof(u16)); | 120 | for (size_t i = 0; i < sample_count; ++i) { |
| 121 | std::memcpy(&ret[i], data + i * sizeof(s16) * 2, 2 * sizeof(s16)); | ||
| 122 | } | ||
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | return ret; | 125 | return ret; |
diff --git a/src/audio_core/codec.h b/src/audio_core/codec.h index 2b0c395e6..877b2202d 100644 --- a/src/audio_core/codec.h +++ b/src/audio_core/codec.h | |||
| @@ -5,13 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <deque> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | 10 | ||
| 11 | namespace Codec { | 11 | namespace Codec { |
| 12 | 12 | ||
| 13 | /// A variable length buffer of signed PCM16 stereo samples. | 13 | /// A variable length buffer of signed PCM16 stereo samples. |
| 14 | using StereoBuffer16 = std::vector<std::array<s16, 2>>; | 14 | using StereoBuffer16 = std::deque<std::array<s16, 2>>; |
| 15 | 15 | ||
| 16 | /// See: Codec::DecodeADPCM | 16 | /// See: Codec::DecodeADPCM |
| 17 | struct ADPCMState { | 17 | struct ADPCMState { |
diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp index 92484c526..c12287700 100644 --- a/src/audio_core/hle/source.cpp +++ b/src/audio_core/hle/source.cpp | |||
| @@ -244,17 +244,27 @@ void Source::GenerateFrame() { | |||
| 244 | break; | 244 | break; |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | const size_t size_to_copy = | 247 | switch (state.interpolation_mode) { |
| 248 | std::min(state.current_buffer.size(), current_frame.size() - frame_position); | 248 | case InterpolationMode::None: |
| 249 | 249 | AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier, | |
| 250 | std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy, | 250 | current_frame, frame_position); |
| 251 | current_frame.begin() + frame_position); | 251 | break; |
| 252 | state.current_buffer.erase(state.current_buffer.begin(), | 252 | case InterpolationMode::Linear: |
| 253 | state.current_buffer.begin() + size_to_copy); | 253 | AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier, |
| 254 | 254 | current_frame, frame_position); | |
| 255 | frame_position += size_to_copy; | 255 | break; |
| 256 | state.next_sample_number += static_cast<u32>(size_to_copy); | 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 | } | ||
| 257 | } | 266 | } |
| 267 | state.next_sample_number += static_cast<u32>(frame_position); | ||
| 258 | 268 | ||
| 259 | state.filters.ProcessFrame(current_frame); | 269 | state.filters.ProcessFrame(current_frame); |
| 260 | } | 270 | } |
| @@ -305,25 +315,6 @@ bool Source::DequeueBuffer() { | |||
| 305 | return true; | 315 | return true; |
| 306 | } | 316 | } |
| 307 | 317 | ||
| 308 | switch (state.interpolation_mode) { | ||
| 309 | case InterpolationMode::None: | ||
| 310 | state.current_buffer = | ||
| 311 | AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier); | ||
| 312 | break; | ||
| 313 | case InterpolationMode::Linear: | ||
| 314 | state.current_buffer = | ||
| 315 | AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||
| 316 | break; | ||
| 317 | case InterpolationMode::Polyphase: | ||
| 318 | // TODO(merry): Implement polyphase interpolation | ||
| 319 | state.current_buffer = | ||
| 320 | AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||
| 321 | break; | ||
| 322 | default: | ||
| 323 | UNIMPLEMENTED(); | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | |||
| 327 | // the first playthrough starts at play_position, loops start at the beginning of the buffer | 318 | // the first playthrough starts at play_position, loops start at the beginning of the buffer |
| 328 | state.current_sample_number = (!buf.has_played) ? buf.play_position : 0; | 319 | state.current_sample_number = (!buf.has_played) ? buf.play_position : 0; |
| 329 | state.next_sample_number = state.current_sample_number; | 320 | state.next_sample_number = state.current_sample_number; |
diff --git a/src/audio_core/hle/source.h b/src/audio_core/hle/source.h index ccb7f064f..c4d2debc2 100644 --- a/src/audio_core/hle/source.h +++ b/src/audio_core/hle/source.h | |||
| @@ -108,7 +108,7 @@ private: | |||
| 108 | 108 | ||
| 109 | u32 current_sample_number = 0; | 109 | u32 current_sample_number = 0; |
| 110 | u32 next_sample_number = 0; | 110 | u32 next_sample_number = 0; |
| 111 | std::vector<std::array<s16, 2>> current_buffer; | 111 | AudioInterp::StereoBuffer16 current_buffer; |
| 112 | 112 | ||
| 113 | // buffer_id state | 113 | // buffer_id state |
| 114 | 114 | ||
diff --git a/src/audio_core/interpolate.cpp b/src/audio_core/interpolate.cpp index 8a5d4181a..83573d772 100644 --- a/src/audio_core/interpolate.cpp +++ b/src/audio_core/interpolate.cpp | |||
| @@ -13,74 +13,64 @@ namespace AudioInterp { | |||
| 13 | constexpr u64 scale_factor = 1 << 24; | 13 | constexpr u64 scale_factor = 1 << 24; |
| 14 | constexpr u64 scale_mask = scale_factor - 1; | 14 | constexpr u64 scale_mask = scale_factor - 1; |
| 15 | 15 | ||
| 16 | /// Here we step over the input in steps of rate_multiplier, until we consume all of the input. | 16 | /// Here we step over the input in steps of rate, until we consume all of the input. |
| 17 | /// Three adjacent samples are passed to fn each step. | 17 | /// Three adjacent samples are passed to fn each step. |
| 18 | template <typename Function> | 18 | template <typename Function> |
| 19 | static StereoBuffer16 StepOverSamples(State& state, const StereoBuffer16& input, | 19 | static void StepOverSamples(State& state, StereoBuffer16& input, float rate, |
| 20 | float rate_multiplier, Function fn) { | 20 | DSP::HLE::StereoFrame16& output, size_t& outputi, Function fn) { |
| 21 | ASSERT(rate_multiplier > 0); | 21 | ASSERT(rate > 0); |
| 22 | 22 | ||
| 23 | if (input.size() < 2) | 23 | if (input.empty()) |
| 24 | return {}; | 24 | return; |
| 25 | 25 | ||
| 26 | StereoBuffer16 output; | 26 | input.insert(input.begin(), {state.xn2, state.xn1}); |
| 27 | output.reserve(static_cast<size_t>(input.size() / rate_multiplier)); | ||
| 28 | 27 | ||
| 29 | u64 step_size = static_cast<u64>(rate_multiplier * scale_factor); | 28 | const u64 step_size = static_cast<u64>(rate * scale_factor); |
| 29 | u64 fposition = state.fposition; | ||
| 30 | size_t inputi = 0; | ||
| 30 | 31 | ||
| 31 | u64 fposition = 0; | 32 | while (outputi < output.size()) { |
| 32 | const u64 max_fposition = input.size() * scale_factor; | 33 | inputi = static_cast<size_t>(fposition / scale_factor); |
| 33 | 34 | ||
| 34 | while (fposition < 1 * scale_factor) { | 35 | if (inputi + 2 >= input.size()) { |
| 35 | u64 fraction = fposition & scale_mask; | 36 | inputi = input.size() - 2; |
| 36 | 37 | break; | |
| 37 | output.push_back(fn(fraction, state.xn2, state.xn1, input[0])); | 38 | } |
| 38 | |||
| 39 | fposition += step_size; | ||
| 40 | } | ||
| 41 | |||
| 42 | while (fposition < 2 * scale_factor) { | ||
| 43 | u64 fraction = fposition & scale_mask; | ||
| 44 | |||
| 45 | output.push_back(fn(fraction, state.xn1, input[0], input[1])); | ||
| 46 | |||
| 47 | fposition += step_size; | ||
| 48 | } | ||
| 49 | 39 | ||
| 50 | while (fposition < max_fposition) { | ||
| 51 | u64 fraction = fposition & scale_mask; | 40 | u64 fraction = fposition & scale_mask; |
| 52 | 41 | output[outputi++] = fn(fraction, input[inputi], input[inputi + 1], input[inputi + 2]); | |
| 53 | size_t index = static_cast<size_t>(fposition / scale_factor); | ||
| 54 | output.push_back(fn(fraction, input[index - 2], input[index - 1], input[index])); | ||
| 55 | 42 | ||
| 56 | fposition += step_size; | 43 | fposition += step_size; |
| 57 | } | 44 | } |
| 58 | 45 | ||
| 59 | state.xn2 = input[input.size() - 2]; | 46 | state.xn2 = input[inputi]; |
| 60 | state.xn1 = input[input.size() - 1]; | 47 | state.xn1 = input[inputi + 1]; |
| 48 | state.fposition = fposition - inputi * scale_factor; | ||
| 61 | 49 | ||
| 62 | return output; | 50 | input.erase(input.begin(), std::next(input.begin(), inputi + 2)); |
| 63 | } | 51 | } |
| 64 | 52 | ||
| 65 | StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multiplier) { | 53 | void None(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output, |
| 66 | return StepOverSamples( | 54 | size_t& outputi) { |
| 67 | state, input, rate_multiplier, | 55 | StepOverSamples( |
| 56 | state, input, rate, output, outputi, | ||
| 68 | [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { return x0; }); | 57 | [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { return x0; }); |
| 69 | } | 58 | } |
| 70 | 59 | ||
| 71 | StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier) { | 60 | void Linear(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output, |
| 61 | size_t& outputi) { | ||
| 72 | // Note on accuracy: Some values that this produces are +/- 1 from the actual firmware. | 62 | // Note on accuracy: Some values that this produces are +/- 1 from the actual firmware. |
| 73 | return StepOverSamples(state, input, rate_multiplier, | 63 | StepOverSamples(state, input, rate, output, outputi, |
| 74 | [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { | 64 | [](u64 fraction, const auto& x0, const auto& x1, const auto& x2) { |
| 75 | // This is a saturated subtraction. (Verified by black-box fuzzing.) | 65 | // This is a saturated subtraction. (Verified by black-box fuzzing.) |
| 76 | s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767); | 66 | s64 delta0 = MathUtil::Clamp<s64>(x1[0] - x0[0], -32768, 32767); |
| 77 | s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767); | 67 | s64 delta1 = MathUtil::Clamp<s64>(x1[1] - x0[1], -32768, 32767); |
| 78 | 68 | ||
| 79 | return std::array<s16, 2>{ | 69 | return std::array<s16, 2>{ |
| 80 | static_cast<s16>(x0[0] + fraction * delta0 / scale_factor), | 70 | static_cast<s16>(x0[0] + fraction * delta0 / scale_factor), |
| 81 | static_cast<s16>(x0[1] + fraction * delta1 / scale_factor), | 71 | static_cast<s16>(x0[1] + fraction * delta1 / scale_factor), |
| 82 | }; | 72 | }; |
| 83 | }); | 73 | }); |
| 84 | } | 74 | } |
| 85 | 75 | ||
| 86 | } // namespace AudioInterp | 76 | } // namespace AudioInterp |
diff --git a/src/audio_core/interpolate.h b/src/audio_core/interpolate.h index 19a7b66cb..8dff6111a 100644 --- a/src/audio_core/interpolate.h +++ b/src/audio_core/interpolate.h | |||
| @@ -5,40 +5,45 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <deque> |
| 9 | #include "audio_core/hle/common.h" | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | 11 | ||
| 11 | namespace AudioInterp { | 12 | namespace AudioInterp { |
| 12 | 13 | ||
| 13 | /// A variable length buffer of signed PCM16 stereo samples. | 14 | /// A variable length buffer of signed PCM16 stereo samples. |
| 14 | using StereoBuffer16 = std::vector<std::array<s16, 2>>; | 15 | using StereoBuffer16 = std::deque<std::array<s16, 2>>; |
| 15 | 16 | ||
| 16 | struct State { | 17 | struct State { |
| 17 | // Two historical samples. | 18 | /// Two historical samples. |
| 18 | std::array<s16, 2> xn1 = {}; ///< x[n-1] | 19 | std::array<s16, 2> xn1 = {}; ///< x[n-1] |
| 19 | std::array<s16, 2> xn2 = {}; ///< x[n-2] | 20 | std::array<s16, 2> xn2 = {}; ///< x[n-2] |
| 21 | /// Current fractional position. | ||
| 22 | u64 fposition = 0; | ||
| 20 | }; | 23 | }; |
| 21 | 24 | ||
| 22 | /** | 25 | /** |
| 23 | * No interpolation. This is equivalent to a zero-order hold. There is a two-sample predelay. | 26 | * No interpolation. This is equivalent to a zero-order hold. There is a two-sample predelay. |
| 24 | * @param state Interpolation state. | 27 | * @param state Interpolation state. |
| 25 | * @param input Input buffer. | 28 | * @param input Input buffer. |
| 26 | * @param rate_multiplier Stretch factor. Must be a positive non-zero value. | 29 | * @param rate Stretch factor. Must be a positive non-zero value. |
| 27 | * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 | 30 | * rate > 1.0 performs decimation and rate < 1.0 performs upsampling. |
| 28 | * performs upsampling. | 31 | * @param output The resampled audio buffer. |
| 29 | * @return The resampled audio buffer. | 32 | * @param outputi The index of output to start writing to. |
| 30 | */ | 33 | */ |
| 31 | StereoBuffer16 None(State& state, const StereoBuffer16& input, float rate_multiplier); | 34 | void None(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output, |
| 35 | size_t& outputi); | ||
| 32 | 36 | ||
| 33 | /** | 37 | /** |
| 34 | * Linear interpolation. This is equivalent to a first-order hold. There is a two-sample predelay. | 38 | * Linear interpolation. This is equivalent to a first-order hold. There is a two-sample predelay. |
| 35 | * @param state Interpolation state. | 39 | * @param state Interpolation state. |
| 36 | * @param input Input buffer. | 40 | * @param input Input buffer. |
| 37 | * @param rate_multiplier Stretch factor. Must be a positive non-zero value. | 41 | * @param rate Stretch factor. Must be a positive non-zero value. |
| 38 | * rate_multiplier > 1.0 performs decimation and rate_multipler < 1.0 | 42 | * rate > 1.0 performs decimation and rate < 1.0 performs upsampling. |
| 39 | * performs upsampling. | 43 | * @param output The resampled audio buffer. |
| 40 | * @return The resampled audio buffer. | 44 | * @param outputi The index of output to start writing to. |
| 41 | */ | 45 | */ |
| 42 | StereoBuffer16 Linear(State& state, const StereoBuffer16& input, float rate_multiplier); | 46 | void Linear(State& state, StereoBuffer16& input, float rate, DSP::HLE::StereoFrame16& output, |
| 47 | size_t& outputi); | ||
| 43 | 48 | ||
| 44 | } // namespace AudioInterp | 49 | } // namespace AudioInterp |