mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Merge pull request #1572 from MerryMage/audio-filter
DSP: Implement audio filters (simple, biquad)
This commit is contained in:
		
						commit
						644fbbeb13
					
				@ -2,13 +2,16 @@ set(SRCS
 | 
				
			|||||||
            audio_core.cpp
 | 
					            audio_core.cpp
 | 
				
			||||||
            codec.cpp
 | 
					            codec.cpp
 | 
				
			||||||
            hle/dsp.cpp
 | 
					            hle/dsp.cpp
 | 
				
			||||||
 | 
					            hle/filter.cpp
 | 
				
			||||||
            hle/pipe.cpp
 | 
					            hle/pipe.cpp
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(HEADERS
 | 
					set(HEADERS
 | 
				
			||||||
            audio_core.h
 | 
					            audio_core.h
 | 
				
			||||||
            codec.h
 | 
					            codec.h
 | 
				
			||||||
 | 
					            hle/common.h
 | 
				
			||||||
            hle/dsp.h
 | 
					            hle/dsp.h
 | 
				
			||||||
 | 
					            hle/filter.h
 | 
				
			||||||
            hle/pipe.h
 | 
					            hle/pipe.h
 | 
				
			||||||
            sink.h
 | 
					            sink.h
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								src/audio_core/hle/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/audio_core/hle/common.h
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
				
			||||||
@ -126,8 +126,11 @@ struct SourceConfiguration {
 | 
				
			|||||||
        union {
 | 
					        union {
 | 
				
			||||||
            u32_le dirty_raw;
 | 
					            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<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<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<16, 1, u32_le> enable_dirty;
 | 
				
			||||||
            BitField<17, 1, u32_le> interpolation_dirty;
 | 
					            BitField<17, 1, u32_le> interpolation_dirty;
 | 
				
			||||||
@ -143,8 +146,7 @@ struct SourceConfiguration {
 | 
				
			|||||||
            BitField<27, 1, u32_le> gain_2_dirty;
 | 
					            BitField<27, 1, u32_le> gain_2_dirty;
 | 
				
			||||||
            BitField<28, 1, u32_le> sync_dirty;
 | 
					            BitField<28, 1, u32_le> sync_dirty;
 | 
				
			||||||
            BitField<29, 1, u32_le> reset_flag;
 | 
					            BitField<29, 1, u32_le> reset_flag;
 | 
				
			||||||
 | 
					            BitField<30, 1, u32_le> embedded_buffer_dirty;
 | 
				
			||||||
            BitField<31, 1, u32_le> embedded_buffer_dirty;
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Gain control
 | 
					        // Gain control
 | 
				
			||||||
@ -175,7 +177,8 @@ struct SourceConfiguration {
 | 
				
			|||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * This is the simplest normalized first-order digital recursive filter.
 | 
					         * This is the simplest normalized first-order digital recursive filter.
 | 
				
			||||||
         * The transfer function of this filter is:
 | 
					         * 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.
 | 
					         * Values are signed fixed point with 15 fractional bits.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        struct SimpleFilter {
 | 
					        struct SimpleFilter {
 | 
				
			||||||
@ -192,11 +195,11 @@ struct SourceConfiguration {
 | 
				
			|||||||
         * Values are signed fixed point with 14 fractional bits.
 | 
					         * Values are signed fixed point with 14 fractional bits.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        struct BiquadFilter {
 | 
					        struct BiquadFilter {
 | 
				
			||||||
            s16_le b0;
 | 
					 | 
				
			||||||
            s16_le b1;
 | 
					 | 
				
			||||||
            s16_le b2;
 | 
					 | 
				
			||||||
            s16_le a1;
 | 
					 | 
				
			||||||
            s16_le a2;
 | 
					            s16_le a2;
 | 
				
			||||||
 | 
					            s16_le a1;
 | 
				
			||||||
 | 
					            s16_le b2;
 | 
				
			||||||
 | 
					            s16_le b1;
 | 
				
			||||||
 | 
					            s16_le b0;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        union {
 | 
					        union {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										115
									
								
								src/audio_core/hle/filter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/audio_core/hle/filter.cpp
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/audio_core/hle/filter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/audio_core/hle/filter.h
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user