diff options
| -rw-r--r-- | src/audio_core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/audio_core/hle/common.h | 35 | ||||
| -rw-r--r-- | src/audio_core/hle/dsp.h | 17 | ||||
| -rw-r--r-- | src/audio_core/hle/filter.cpp | 115 | ||||
| -rw-r--r-- | src/audio_core/hle/filter.h | 112 | 
5 files changed, 275 insertions, 7 deletions
| diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index c4bad8cb0..869da5e83 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -2,13 +2,16 @@ set(SRCS              audio_core.cpp              codec.cpp              hle/dsp.cpp +            hle/filter.cpp              hle/pipe.cpp              )  set(HEADERS              audio_core.h              codec.h +            hle/common.h              hle/dsp.h +            hle/filter.h              hle/pipe.h              sink.h              ) diff --git a/src/audio_core/hle/common.h b/src/audio_core/hle/common.h new file mode 100644 index 000000000..37d441eb2 --- /dev/null +++ b/src/audio_core/hle/common.h @@ -0,0 +1,35 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <algorithm> +#include <array> + +#include "audio_core/audio_core.h" + +#include "common/common_types.h" + +namespace DSP { +namespace HLE { + +/// The final output to the speakers is stereo. Preprocessing output in Source is also stereo. +using StereoFrame16 = std::array<std::array<s16, 2>, AudioCore::samples_per_frame>; + +/// The DSP is quadraphonic internally. +using QuadFrame32   = std::array<std::array<s32, 4>, AudioCore::samples_per_frame>; + +/** + * This performs the filter operation defined by FilterT::ProcessSample on the frame in-place. + * FilterT::ProcessSample is called sequentially on the samples. + */ +template<typename FrameT, typename FilterT> +void FilterFrame(FrameT& frame, FilterT& filter) { +    std::transform(frame.begin(), frame.end(), frame.begin(), [&filter](const typename FrameT::value_type& sample) { +        return filter.ProcessSample(sample); +    }); +} + +} // namespace HLE +} // namespace DSP diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h index 376436c29..c15ef0b7a 100644 --- a/src/audio_core/hle/dsp.h +++ b/src/audio_core/hle/dsp.h @@ -126,8 +126,11 @@ struct SourceConfiguration {          union {              u32_le dirty_raw; +            BitField<0, 1, u32_le> format_dirty; +            BitField<1, 1, u32_le> mono_or_stereo_dirty;              BitField<2, 1, u32_le> adpcm_coefficients_dirty;              BitField<3, 1, u32_le> partial_embedded_buffer_dirty; ///< Tends to be set when a looped buffer is queued. +            BitField<4, 1, u32_le> partial_reset_flag;              BitField<16, 1, u32_le> enable_dirty;              BitField<17, 1, u32_le> interpolation_dirty; @@ -143,8 +146,7 @@ struct SourceConfiguration {              BitField<27, 1, u32_le> gain_2_dirty;              BitField<28, 1, u32_le> sync_dirty;              BitField<29, 1, u32_le> reset_flag; - -            BitField<31, 1, u32_le> embedded_buffer_dirty; +            BitField<30, 1, u32_le> embedded_buffer_dirty;          };          // Gain control @@ -175,7 +177,8 @@ struct SourceConfiguration {          /**           * This is the simplest normalized first-order digital recursive filter.           * The transfer function of this filter is: -         *     H(z) = b0 / (1 + a1 z^-1) +         *     H(z) = b0 / (1 - a1 z^-1) +         * Note the feedbackward coefficient is negated.           * Values are signed fixed point with 15 fractional bits.           */          struct SimpleFilter { @@ -192,11 +195,11 @@ struct SourceConfiguration {           * Values are signed fixed point with 14 fractional bits.           */          struct BiquadFilter { -            s16_le b0; -            s16_le b1; -            s16_le b2; -            s16_le a1;              s16_le a2; +            s16_le a1; +            s16_le b2; +            s16_le b1; +            s16_le b0;          };          union { diff --git a/src/audio_core/hle/filter.cpp b/src/audio_core/hle/filter.cpp new file mode 100644 index 000000000..2c65ef026 --- /dev/null +++ b/src/audio_core/hle/filter.cpp @@ -0,0 +1,115 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include <cstddef> + +#include "audio_core/hle/common.h" +#include "audio_core/hle/dsp.h" +#include "audio_core/hle/filter.h" + +#include "common/common_types.h" +#include "common/math_util.h" + +namespace DSP { +namespace HLE { + +void SourceFilters::Reset() { +    Enable(false, false); +} + +void SourceFilters::Enable(bool simple, bool biquad) { +    simple_filter_enabled = simple; +    biquad_filter_enabled = biquad; + +    if (!simple) +        simple_filter.Reset(); +    if (!biquad) +        biquad_filter.Reset(); +} + +void SourceFilters::Configure(SourceConfiguration::Configuration::SimpleFilter config) { +    simple_filter.Configure(config); +} + +void SourceFilters::Configure(SourceConfiguration::Configuration::BiquadFilter config) { +    biquad_filter.Configure(config); +} + +void SourceFilters::ProcessFrame(StereoFrame16& frame) { +    if (!simple_filter_enabled && !biquad_filter_enabled) +        return; + +    if (simple_filter_enabled) { +        FilterFrame(frame, simple_filter); +    } + +    if (biquad_filter_enabled) { +        FilterFrame(frame, biquad_filter); +    } +} + +// SimpleFilter + +void SourceFilters::SimpleFilter::Reset() { +    y1.fill(0); +    // Configure as passthrough. +    a1 = 0; +    b0 = 1 << 15; +} + +void SourceFilters::SimpleFilter::Configure(SourceConfiguration::Configuration::SimpleFilter config) { +    a1 = config.a1; +    b0 = config.b0; +} + +std::array<s16, 2> SourceFilters::SimpleFilter::ProcessSample(const std::array<s16, 2>& x0) { +    std::array<s16, 2> y0; +    for (size_t i = 0; i < 2; i++) { +        const s32 tmp = (b0 * x0[i] + a1 * y1[i]) >> 15; +        y0[i] = MathUtil::Clamp(tmp, -32768, 32767); +    } + +    y1 = y0; + +    return y0; +} + +// BiquadFilter + +void SourceFilters::BiquadFilter::Reset() { +    x1.fill(0); +    x2.fill(0); +    y1.fill(0); +    y2.fill(0); +    // Configure as passthrough. +    a1 = a2 = b1 = b2 = 0; +    b0 = 1 << 14; +} + +void SourceFilters::BiquadFilter::Configure(SourceConfiguration::Configuration::BiquadFilter config) { +    a1 = config.a1; +    a2 = config.a2; +    b0 = config.b0; +    b1 = config.b1; +    b2 = config.b2; +} + +std::array<s16, 2> SourceFilters::BiquadFilter::ProcessSample(const std::array<s16, 2>& x0) { +    std::array<s16, 2> y0; +    for (size_t i = 0; i < 2; i++) { +        const s32 tmp = (b0 * x0[i] + b1 * x1[i] + b2 * x2[i] + a1 * y1[i] + a2 * y2[i]) >> 14; +        y0[i] = MathUtil::Clamp(tmp, -32768, 32767); +    } + +    x2 = x1; +    x1 = x0; +    y2 = y1; +    y1 = y0; + +    return y0; +} + +} // namespace HLE +} // namespace DSP diff --git a/src/audio_core/hle/filter.h b/src/audio_core/hle/filter.h new file mode 100644 index 000000000..75738f600 --- /dev/null +++ b/src/audio_core/hle/filter.h @@ -0,0 +1,112 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> + +#include "audio_core/hle/common.h" +#include "audio_core/hle/dsp.h" + +#include "common/common_types.h" + +namespace DSP { +namespace HLE { + +/// Preprocessing filters. There is an independent set of filters for each Source. +class SourceFilters final { +    SourceFilters() { Reset(); } + +    /// Reset internal state. +    void Reset(); + +    /** +     * Enable/Disable filters +     * See also: SourceConfiguration::Configuration::simple_filter_enabled, +     *           SourceConfiguration::Configuration::biquad_filter_enabled. +     * @param simple If true, enables the simple filter. If false, disables it. +     * @param simple If true, enables the biquad filter. If false, disables it. +     */ +    void Enable(bool simple, bool biquad); + +    /** +     * Configure simple filter. +     * @param config Configuration from DSP shared memory. +     */ +    void Configure(SourceConfiguration::Configuration::SimpleFilter config); + +    /** +     * Configure biquad filter. +     * @param config Configuration from DSP shared memory. +     */ +    void Configure(SourceConfiguration::Configuration::BiquadFilter config); + +    /** +     * Processes a frame in-place. +     * @param frame Audio samples to process. Modified in-place. +     */ +    void ProcessFrame(StereoFrame16& frame); + +private: +    bool simple_filter_enabled; +    bool biquad_filter_enabled; + +    struct SimpleFilter { +        SimpleFilter() { Reset(); } + +        /// Resets internal state. +        void Reset(); + +        /** +         * Configures this filter with application settings. +         * @param config Configuration from DSP shared memory. +         */ +        void Configure(SourceConfiguration::Configuration::SimpleFilter config); + +        /** +         * Processes a single stereo PCM16 sample. +         * @param x0 Input sample +         * @return Output sample +         */ +        std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0); + +    private: +        // Configuration +        s32 a1, b0; +        // Internal state +        std::array<s16, 2> y1; +    } simple_filter; + +    struct BiquadFilter { +        BiquadFilter() { Reset(); } + +        /// Resets internal state. +        void Reset(); + +        /** +         * Configures this filter with application settings. +         * @param config Configuration from DSP shared memory. +         */ +        void Configure(SourceConfiguration::Configuration::BiquadFilter config); + +        /** +         * Processes a single stereo PCM16 sample. +         * @param x0 Input sample +         * @return Output sample +         */ +        std::array<s16, 2> ProcessSample(const std::array<s16, 2>& x0); + +    private: +        // Configuration +        s32 a1, a2, b0, b1, b2; +        // Internal state +        std::array<s16, 2> x1; +        std::array<s16, 2> x2; +        std::array<s16, 2> y1; +        std::array<s16, 2> y2; +    } biquad_filter; +}; + +} // namespace HLE +} // namespace DSP | 
