mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Sources: Run clang-format on everything.
This commit is contained in:
		
							parent
							
								
									fe948af095
								
							
						
					
					
						commit
						dc8479928c
					
				
					 386 changed files with 19560 additions and 18080 deletions
				
			
		|  | @ -13,23 +13,22 @@ namespace DSP { | |||
| namespace HLE { | ||||
| 
 | ||||
| constexpr int num_sources = 24; | ||||
| constexpr int samples_per_frame = 160;     ///< Samples per audio frame at native sample rate
 | ||||
| constexpr int samples_per_frame = 160; ///< Samples per audio frame at native sample rate
 | ||||
| 
 | ||||
| /// The final output to the speakers is stereo. Preprocessing output in Source is also stereo.
 | ||||
| using StereoFrame16 = std::array<std::array<s16, 2>, samples_per_frame>; | ||||
| 
 | ||||
| /// The DSP is quadraphonic internally.
 | ||||
| using QuadFrame32   = std::array<std::array<s32, 4>, samples_per_frame>; | ||||
| using QuadFrame32 = std::array<std::array<s32, 4>, 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> | ||||
| template <typename FrameT, typename FilterT> | ||||
| void FilterFrame(FrameT& frame, FilterT& filter) { | ||||
|     std::transform(frame.begin(), frame.end(), frame.begin(), [&filter](const auto& sample) { | ||||
|         return filter.ProcessSample(sample); | ||||
|     }); | ||||
|     std::transform(frame.begin(), frame.end(), frame.begin(), | ||||
|                    [&filter](const auto& sample) { return filter.ProcessSample(sample); }); | ||||
| } | ||||
| 
 | ||||
| } // namespace HLE
 | ||||
|  |  | |||
|  | @ -47,11 +47,9 @@ static SharedMemory& WriteRegion() { | |||
| // Audio processing and mixing
 | ||||
| 
 | ||||
| static std::array<Source, num_sources> sources = { | ||||
|     Source(0), Source(1), Source(2), Source(3), Source(4), Source(5), | ||||
|     Source(6), Source(7), Source(8), Source(9), Source(10), Source(11), | ||||
|     Source(12), Source(13), Source(14), Source(15), Source(16), Source(17), | ||||
|     Source(18), Source(19), Source(20), Source(21), Source(22), Source(23) | ||||
| }; | ||||
|     Source(0),  Source(1),  Source(2),  Source(3),  Source(4),  Source(5),  Source(6),  Source(7), | ||||
|     Source(8),  Source(9),  Source(10), Source(11), Source(12), Source(13), Source(14), Source(15), | ||||
|     Source(16), Source(17), Source(18), Source(19), Source(20), Source(21), Source(22), Source(23)}; | ||||
| static Mixers mixers; | ||||
| 
 | ||||
| static StereoFrame16 GenerateCurrentFrame() { | ||||
|  | @ -62,14 +60,16 @@ static StereoFrame16 GenerateCurrentFrame() { | |||
| 
 | ||||
|     // Generate intermediate mixes
 | ||||
|     for (size_t i = 0; i < num_sources; i++) { | ||||
|         write.source_statuses.status[i] = sources[i].Tick(read.source_configurations.config[i], read.adpcm_coefficients.coeff[i]); | ||||
|         write.source_statuses.status[i] = | ||||
|             sources[i].Tick(read.source_configurations.config[i], read.adpcm_coefficients.coeff[i]); | ||||
|         for (size_t mix = 0; mix < 3; mix++) { | ||||
|             sources[i].MixInto(intermediate_mixes[mix], mix); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Generate final mix
 | ||||
|     write.dsp_status = mixers.Tick(read.dsp_configuration, read.intermediate_mix_samples, write.intermediate_mix_samples, intermediate_mixes); | ||||
|     write.dsp_status = mixers.Tick(read.dsp_configuration, read.intermediate_mix_samples, | ||||
|                                    write.intermediate_mix_samples, intermediate_mixes); | ||||
| 
 | ||||
|     StereoFrame16 output_frame = mixers.GetOutput(); | ||||
| 
 | ||||
|  | @ -152,7 +152,8 @@ void Shutdown() { | |||
| bool Tick() { | ||||
|     StereoFrame16 current_frame = {}; | ||||
| 
 | ||||
|     // TODO: Check dsp::DSP semaphore (which indicates emulated application has finished writing to shared memory region)
 | ||||
|     // TODO: Check dsp::DSP semaphore (which indicates emulated application has finished writing to
 | ||||
|     // shared memory region)
 | ||||
|     current_frame = GenerateCurrentFrame(); | ||||
| 
 | ||||
|     OutputCurrentFrame(current_frame); | ||||
|  |  | |||
|  | @ -30,7 +30,8 @@ namespace HLE { | |||
| // Second Region: 0x1FF70000 (Size: 0x8000)
 | ||||
| //
 | ||||
| // The DSP reads from each region alternately based on the frame counter for each region much like a
 | ||||
| // double-buffer. The frame counter is located as the very last u16 of each region and is incremented
 | ||||
| // double-buffer. The frame counter is located as the very last u16 of each region and is
 | ||||
| // incremented
 | ||||
| // each audio tick.
 | ||||
| 
 | ||||
| constexpr VAddr region0_base = 0x1FF50000; | ||||
|  | @ -56,6 +57,7 @@ struct u32_dsp { | |||
|     void operator=(u32 new_value) { | ||||
|         storage = Convert(new_value); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     static constexpr u32 Convert(u32 value) { | ||||
|         return (value << 16) | (value >> 16); | ||||
|  | @ -89,11 +91,13 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial | |||
| // #: This refers to the order in which they appear in the DspPipe::Audio DSP pipe.
 | ||||
| //    See also: DSP::HLE::PipeRead.
 | ||||
| //
 | ||||
| // Note that the above addresses do vary slightly between audio firmwares observed; the addresses are
 | ||||
| // Note that the above addresses do vary slightly between audio firmwares observed; the addresses
 | ||||
| // are
 | ||||
| // not fixed in stone. The addresses above are only an examplar; they're what this implementation
 | ||||
| // does and provides to applications.
 | ||||
| //
 | ||||
| // Application requests the DSP service to convert DSP addresses into ARM11 virtual addresses using the
 | ||||
| // Application requests the DSP service to convert DSP addresses into ARM11 virtual addresses using
 | ||||
| // the
 | ||||
| // ConvertProcessAddressFromDspDram service call. Applications seem to derive the addresses for the
 | ||||
| // second region via:
 | ||||
| //     second_region_dsp_addr = first_region_dsp_addr | 0x10000
 | ||||
|  | @ -110,14 +114,17 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial | |||
| // GCC versions < 5.0 do not implement std::is_trivially_copyable.
 | ||||
| // Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
 | ||||
| #if (__GNUC__ >= 5) || defined(__clang__) | ||||
|     #define ASSERT_DSP_STRUCT(name, size) \ | ||||
|         static_assert(std::is_standard_layout<name>::value, "DSP structure " #name " doesn't use standard layout"); \ | ||||
|         static_assert(std::is_trivially_copyable<name>::value, "DSP structure " #name " isn't trivially copyable"); \ | ||||
|         static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name) | ||||
| #define ASSERT_DSP_STRUCT(name, size)                                                              \ | ||||
|     static_assert(std::is_standard_layout<name>::value,                                            \ | ||||
|                   "DSP structure " #name " doesn't use standard layout");                          \ | ||||
|     static_assert(std::is_trivially_copyable<name>::value,                                         \ | ||||
|                   "DSP structure " #name " isn't trivially copyable");                             \ | ||||
|     static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name) | ||||
| #else | ||||
|     #define ASSERT_DSP_STRUCT(name, size) \ | ||||
|         static_assert(std::is_standard_layout<name>::value, "DSP structure " #name " doesn't use standard layout"); \ | ||||
|         static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name) | ||||
| #define ASSERT_DSP_STRUCT(name, size)                                                              \ | ||||
|     static_assert(std::is_standard_layout<name>::value,                                            \ | ||||
|                   "DSP structure " #name " doesn't use standard layout");                          \ | ||||
|     static_assert(sizeof(name) == (size), "Unexpected struct size for DSP structure " #name) | ||||
| #endif | ||||
| 
 | ||||
| struct SourceConfiguration { | ||||
|  | @ -130,7 +137,8 @@ struct SourceConfiguration { | |||
|             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<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; | ||||
|  | @ -138,7 +146,8 @@ struct SourceConfiguration { | |||
|             BitField<18, 1, u32_le> rate_multiplier_dirty; | ||||
|             BitField<19, 1, u32_le> buffer_queue_dirty; | ||||
|             BitField<20, 1, u32_le> loop_related_dirty; | ||||
|             BitField<21, 1, u32_le> play_position_dirty; ///< Tends to also be set when embedded buffer is updated.
 | ||||
|             BitField<21, 1, u32_le> | ||||
|                 play_position_dirty; ///< Tends to also be set when embedded buffer is updated.
 | ||||
|             BitField<22, 1, u32_le> filters_enabled_dirty; | ||||
|             BitField<23, 1, u32_le> simple_filter_dirty; | ||||
|             BitField<24, 1, u32_le> biquad_filter_dirty; | ||||
|  | @ -164,11 +173,7 @@ struct SourceConfiguration { | |||
|         /// Multiplier for sample rate. Resampling occurs with the selected interpolation method.
 | ||||
|         float_le rate_multiplier; | ||||
| 
 | ||||
|         enum class InterpolationMode : u8 { | ||||
|             Polyphase = 0, | ||||
|             Linear = 1, | ||||
|             None = 2 | ||||
|         }; | ||||
|         enum class InterpolationMode : u8 { Polyphase = 0, Linear = 1, None = 2 }; | ||||
| 
 | ||||
|         InterpolationMode interpolation_mode; | ||||
|         INSERT_PADDING_BYTES(1); ///< Interpolation related
 | ||||
|  | @ -191,7 +196,8 @@ struct SourceConfiguration { | |||
|          * This is a normalised biquad filter (second-order). | ||||
|          * The transfer function of this filter is: | ||||
|          *     H(z) = (b0 + b1 z^-1 + b2 z^-2) / (1 - a1 z^-1 - a2 z^-2) | ||||
|          * Nintendo chose to negate the feedbackward coefficients. This differs from standard notation | ||||
|          * Nintendo chose to negate the feedbackward coefficients. This differs from standard | ||||
|          * notation | ||||
|          * as in: https://ccrma.stanford.edu/~jos/filters/Direct_Form_I.html
 | ||||
|          * Values are signed fixed point with 14 fractional bits. | ||||
|          */ | ||||
|  | @ -239,23 +245,24 @@ struct SourceConfiguration { | |||
|             /// Is a looping buffer.
 | ||||
|             u8 is_looping; | ||||
| 
 | ||||
|             /// This value is shown in SourceStatus::previous_buffer_id when this buffer has finished.
 | ||||
|             /// This value is shown in SourceStatus::previous_buffer_id when this buffer has
 | ||||
|             /// finished.
 | ||||
|             /// This allows the emulated application to tell what buffer is currently playing
 | ||||
|             u16_le buffer_id; | ||||
| 
 | ||||
|             INSERT_PADDING_DSPWORDS(1); | ||||
|         }; | ||||
| 
 | ||||
|         u16_le buffers_dirty;             ///< Bitmap indicating which buffers are dirty (bit i -> buffers[i])
 | ||||
|         Buffer buffers[4];                ///< Queued Buffers
 | ||||
|         u16_le buffers_dirty; ///< Bitmap indicating which buffers are dirty (bit i -> buffers[i])
 | ||||
|         Buffer buffers[4];    ///< Queued Buffers
 | ||||
| 
 | ||||
|         // Playback controls
 | ||||
| 
 | ||||
|         u32_dsp loop_related; | ||||
|         u8 enable; | ||||
|         INSERT_PADDING_BYTES(1); | ||||
|         u16_le sync;                      ///< Application-side sync (See also: SourceStatus::sync)
 | ||||
|         u32_dsp play_position;            ///< Position. (Units: number of samples)
 | ||||
|         u16_le sync;           ///< Application-side sync (See also: SourceStatus::sync)
 | ||||
|         u32_dsp play_position; ///< Position. (Units: number of samples)
 | ||||
|         INSERT_PADDING_DSPWORDS(2); | ||||
| 
 | ||||
|         // Embedded Buffer
 | ||||
|  | @ -268,16 +275,9 @@ struct SourceConfiguration { | |||
|         /// Note a sample takes up different number of bytes in different buffer formats.
 | ||||
|         u32_dsp length; | ||||
| 
 | ||||
|         enum class MonoOrStereo : u16_le { | ||||
|             Mono = 1, | ||||
|             Stereo = 2 | ||||
|         }; | ||||
|         enum class MonoOrStereo : u16_le { Mono = 1, Stereo = 2 }; | ||||
| 
 | ||||
|         enum class Format : u16_le { | ||||
|             PCM8 = 0, | ||||
|             PCM16 = 1, | ||||
|             ADPCM = 2 | ||||
|         }; | ||||
|         enum class Format : u16_le { PCM8 = 0, PCM16 = 1, ADPCM = 2 }; | ||||
| 
 | ||||
|         union { | ||||
|             u16_le flags1_raw; | ||||
|  | @ -299,10 +299,11 @@ struct SourceConfiguration { | |||
|         union { | ||||
|             u16_le flags2_raw; | ||||
|             BitField<0, 1, u16_le> adpcm_dirty; ///< Has the ADPCM info above been changed?
 | ||||
|             BitField<1, 1, u16_le> is_looping; ///< Is this a looping buffer?
 | ||||
|             BitField<1, 1, u16_le> is_looping;  ///< Is this a looping buffer?
 | ||||
|         }; | ||||
| 
 | ||||
|         /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this buffer).
 | ||||
|         /// Buffer id of embedded buffer (used as a buffer id in SourceStatus to reference this
 | ||||
|         /// buffer).
 | ||||
|         u16_le buffer_id; | ||||
|     }; | ||||
| 
 | ||||
|  | @ -313,11 +314,11 @@ ASSERT_DSP_STRUCT(SourceConfiguration::Configuration::Buffer, 20); | |||
| 
 | ||||
| struct SourceStatus { | ||||
|     struct Status { | ||||
|         u8 is_enabled;               ///< Is this channel enabled? (Doesn't have to be playing anything.)
 | ||||
|         u8 current_buffer_id_dirty;  ///< Non-zero when current_buffer_id changes
 | ||||
|         u16_le sync;                 ///< Is set by the DSP to the value of SourceConfiguration::sync
 | ||||
|         u32_dsp buffer_position;     ///< Number of samples into the current buffer
 | ||||
|         u16_le current_buffer_id;    ///< Updated when a buffer finishes playing
 | ||||
|         u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.)
 | ||||
|         u8 current_buffer_id_dirty; ///< Non-zero when current_buffer_id changes
 | ||||
|         u16_le sync;                ///< Is set by the DSP to the value of SourceConfiguration::sync
 | ||||
|         u32_dsp buffer_position;    ///< Number of samples into the current buffer
 | ||||
|         u16_le current_buffer_id;   ///< Updated when a buffer finishes playing
 | ||||
|         INSERT_PADDING_DSPWORDS(1); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -347,16 +348,13 @@ struct DspConfiguration { | |||
|         BitField<28, 1, u32_le> headphones_connected_dirty; | ||||
|     }; | ||||
| 
 | ||||
|     /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for each at the final mixer
 | ||||
|     /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for
 | ||||
|     /// each at the final mixer
 | ||||
|     float_le volume[3]; | ||||
| 
 | ||||
|     INSERT_PADDING_DSPWORDS(3); | ||||
| 
 | ||||
|     enum class OutputFormat : u16_le { | ||||
|         Mono = 0, | ||||
|         Stereo = 1, | ||||
|         Surround = 2 | ||||
|     }; | ||||
|     enum class OutputFormat : u16_le { Mono = 0, Stereo = 1, Surround = 2 }; | ||||
| 
 | ||||
|     OutputFormat output_format; | ||||
| 
 | ||||
|  | @ -388,8 +386,9 @@ struct DspConfiguration { | |||
|         u16_le enable; | ||||
|         INSERT_PADDING_DSPWORDS(1); | ||||
|         u16_le outputs; | ||||
|         u32_dsp work_buffer_address; ///< The application allocates a block of memory for the DSP to use as a work buffer.
 | ||||
|         u16_le frame_count;  ///< Frames to delay by
 | ||||
|         u32_dsp work_buffer_address; ///< The application allocates a block of memory for the DSP to
 | ||||
|                                      /// use as a work buffer.
 | ||||
|         u16_le frame_count;          ///< Frames to delay by
 | ||||
| 
 | ||||
|         // Coefficients
 | ||||
|         s16_le g; ///< Fixed point with 7 fractional bits
 | ||||
|  | @ -506,21 +505,36 @@ ASSERT_DSP_STRUCT(SharedMemory, 0x8000); | |||
| extern std::array<SharedMemory, 2> g_regions; | ||||
| 
 | ||||
| // Structures must have an offset that is a multiple of two.
 | ||||
| static_assert(offsetof(SharedMemory, frame_counter) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, source_configurations) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, source_statuses) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, adpcm_coefficients) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_configuration) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_status) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, final_samples) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, intermediate_mix_samples) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, compressor) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_debug) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown10) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown11) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown12) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown13) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown14) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, frame_counter) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, source_configurations) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, source_statuses) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, adpcm_coefficients) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_configuration) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_status) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, final_samples) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, intermediate_mix_samples) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, compressor) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, dsp_debug) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown10) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown11) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown12) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown13) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| static_assert(offsetof(SharedMemory, unknown14) % 2 == 0, | ||||
|               "Structures in DSP::HLE::SharedMemory must be 2-byte aligned"); | ||||
| 
 | ||||
| #undef INSERT_PADDING_DSPWORDS | ||||
| #undef ASSERT_DSP_STRUCT | ||||
|  |  | |||
|  | @ -59,7 +59,8 @@ void SourceFilters::SimpleFilter::Reset() { | |||
|     b0 = 1 << 15; | ||||
| } | ||||
| 
 | ||||
| void SourceFilters::SimpleFilter::Configure(SourceConfiguration::Configuration::SimpleFilter config) { | ||||
| void SourceFilters::SimpleFilter::Configure( | ||||
|     SourceConfiguration::Configuration::SimpleFilter config) { | ||||
|     a1 = config.a1; | ||||
|     b0 = config.b0; | ||||
| } | ||||
|  | @ -88,7 +89,8 @@ void SourceFilters::BiquadFilter::Reset() { | |||
|     b0 = 1 << 14; | ||||
| } | ||||
| 
 | ||||
| void SourceFilters::BiquadFilter::Configure(SourceConfiguration::Configuration::BiquadFilter config) { | ||||
| void SourceFilters::BiquadFilter::Configure( | ||||
|     SourceConfiguration::Configuration::BiquadFilter config) { | ||||
|     a1 = config.a1; | ||||
|     a2 = config.a2; | ||||
|     b0 = config.b0; | ||||
|  |  | |||
|  | @ -17,7 +17,9 @@ namespace HLE { | |||
| /// Preprocessing filters. There is an independent set of filters for each Source.
 | ||||
| class SourceFilters final { | ||||
| public: | ||||
|     SourceFilters() { Reset(); } | ||||
|     SourceFilters() { | ||||
|         Reset(); | ||||
|     } | ||||
| 
 | ||||
|     /// Reset internal state.
 | ||||
|     void Reset(); | ||||
|  | @ -54,7 +56,9 @@ private: | |||
|     bool biquad_filter_enabled; | ||||
| 
 | ||||
|     struct SimpleFilter { | ||||
|         SimpleFilter() { Reset(); } | ||||
|         SimpleFilter() { | ||||
|             Reset(); | ||||
|         } | ||||
| 
 | ||||
|         /// Resets internal state.
 | ||||
|         void Reset(); | ||||
|  | @ -80,7 +84,9 @@ private: | |||
|     } simple_filter; | ||||
| 
 | ||||
|     struct BiquadFilter { | ||||
|         BiquadFilter() { Reset(); } | ||||
|         BiquadFilter() { | ||||
|             Reset(); | ||||
|         } | ||||
| 
 | ||||
|         /// Resets internal state.
 | ||||
|         void Reset(); | ||||
|  |  | |||
|  | @ -20,11 +20,9 @@ void Mixers::Reset() { | |||
|     state = {}; | ||||
| } | ||||
| 
 | ||||
| DspStatus Mixers::Tick(DspConfiguration& config, | ||||
|         const IntermediateMixSamples& read_samples, | ||||
|         IntermediateMixSamples& write_samples, | ||||
|         const std::array<QuadFrame32, 3>& input) | ||||
| { | ||||
| DspStatus Mixers::Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples, | ||||
|                        IntermediateMixSamples& write_samples, | ||||
|                        const std::array<QuadFrame32, 3>& input) { | ||||
|     ParseConfig(config); | ||||
| 
 | ||||
|     AuxReturn(read_samples); | ||||
|  | @ -73,13 +71,15 @@ void Mixers::ParseConfig(DspConfiguration& config) { | |||
|     if (config.output_format_dirty) { | ||||
|         config.output_format_dirty.Assign(0); | ||||
|         state.output_format = config.output_format; | ||||
|         LOG_TRACE(Audio_DSP, "mixers output_format = %zu", static_cast<size_t>(config.output_format)); | ||||
|         LOG_TRACE(Audio_DSP, "mixers output_format = %zu", | ||||
|                   static_cast<size_t>(config.output_format)); | ||||
|     } | ||||
| 
 | ||||
|     if (config.headphones_connected_dirty) { | ||||
|         config.headphones_connected_dirty.Assign(0); | ||||
|         // Do nothing.
 | ||||
|         // (Note: Whether headphones are connected does affect coefficients used for surround sound.)
 | ||||
|         // (Note: Whether headphones are connected does affect coefficients used for surround
 | ||||
|         // sound.)
 | ||||
|         LOG_TRACE(Audio_DSP, "mixers headphones_connected=%hu", config.headphones_connected); | ||||
|     } | ||||
| 
 | ||||
|  | @ -94,11 +94,10 @@ static s16 ClampToS16(s32 value) { | |||
|     return static_cast<s16>(MathUtil::Clamp(value, -32768, 32767)); | ||||
| } | ||||
| 
 | ||||
| static std::array<s16, 2> AddAndClampToS16(const std::array<s16, 2>& a, const std::array<s16, 2>& b) { | ||||
|     return { | ||||
|         ClampToS16(static_cast<s32>(a[0]) + static_cast<s32>(b[0])), | ||||
|         ClampToS16(static_cast<s32>(a[1]) + static_cast<s32>(b[1])) | ||||
|     }; | ||||
| static std::array<s16, 2> AddAndClampToS16(const std::array<s16, 2>& a, | ||||
|                                            const std::array<s16, 2>& b) { | ||||
|     return {ClampToS16(static_cast<s32>(a[0]) + static_cast<s32>(b[0])), | ||||
|             ClampToS16(static_cast<s32>(a[1]) + static_cast<s32>(b[1]))}; | ||||
| } | ||||
| 
 | ||||
| void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples) { | ||||
|  | @ -106,27 +105,33 @@ void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& sample | |||
| 
 | ||||
|     switch (state.output_format) { | ||||
|     case OutputFormat::Mono: | ||||
|         std::transform(current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | ||||
|             [gain](const std::array<s16, 2>& accumulator, const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||||
|         std::transform( | ||||
|             current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | ||||
|             [gain](const std::array<s16, 2>& accumulator, | ||||
|                    const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||||
|                 // Downmix to mono
 | ||||
|                 s16 mono = ClampToS16(static_cast<s32>((gain * sample[0] + gain * sample[1] + gain * sample[2] + gain * sample[3]) / 2)); | ||||
|                 s16 mono = ClampToS16(static_cast<s32>( | ||||
|                     (gain * sample[0] + gain * sample[1] + gain * sample[2] + gain * sample[3]) / | ||||
|                     2)); | ||||
|                 // Mix into current frame
 | ||||
|                 return AddAndClampToS16(accumulator, { mono, mono }); | ||||
|                 return AddAndClampToS16(accumulator, {mono, mono}); | ||||
|             }); | ||||
|         return; | ||||
| 
 | ||||
|     case OutputFormat::Surround: | ||||
|         // TODO(merry): Implement surround sound.
 | ||||
|         // fallthrough
 | ||||
|     // TODO(merry): Implement surround sound.
 | ||||
|     // fallthrough
 | ||||
| 
 | ||||
|     case OutputFormat::Stereo: | ||||
|         std::transform(current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | ||||
|             [gain](const std::array<s16, 2>& accumulator, const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||||
|         std::transform( | ||||
|             current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | ||||
|             [gain](const std::array<s16, 2>& accumulator, | ||||
|                    const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||||
|                 // Downmix to stereo
 | ||||
|                 s16 left = ClampToS16(static_cast<s32>(gain * sample[0] + gain * sample[2])); | ||||
|                 s16 right = ClampToS16(static_cast<s32>(gain * sample[1] + gain * sample[3])); | ||||
|                 // Mix into current frame
 | ||||
|                 return AddAndClampToS16(accumulator, { left, right }); | ||||
|                 return AddAndClampToS16(accumulator, {left, right}); | ||||
|             }); | ||||
|         return; | ||||
|     } | ||||
|  | @ -135,12 +140,14 @@ void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& sample | |||
| } | ||||
| 
 | ||||
| void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) { | ||||
|     // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to QuadFrame32.
 | ||||
|     // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
 | ||||
|     // QuadFrame32.
 | ||||
| 
 | ||||
|     if (state.mixer1_enabled) { | ||||
|         for (size_t sample = 0; sample < samples_per_frame; sample++) { | ||||
|             for (size_t channel = 0; channel < 4; channel++) { | ||||
|                 state.intermediate_mix_buffer[1][sample][channel] = read_samples.mix1.pcm32[channel][sample]; | ||||
|                 state.intermediate_mix_buffer[1][sample][channel] = | ||||
|                     read_samples.mix1.pcm32[channel][sample]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -148,14 +155,17 @@ void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) { | |||
|     if (state.mixer2_enabled) { | ||||
|         for (size_t sample = 0; sample < samples_per_frame; sample++) { | ||||
|             for (size_t channel = 0; channel < 4; channel++) { | ||||
|                 state.intermediate_mix_buffer[2][sample][channel] = read_samples.mix2.pcm32[channel][sample]; | ||||
|                 state.intermediate_mix_buffer[2][sample][channel] = | ||||
|                     read_samples.mix2.pcm32[channel][sample]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Mixers::AuxSend(IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input) { | ||||
|     // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to QuadFrame32.
 | ||||
| void Mixers::AuxSend(IntermediateMixSamples& write_samples, | ||||
|                      const std::array<QuadFrame32, 3>& input) { | ||||
|     // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to
 | ||||
|     // QuadFrame32.
 | ||||
| 
 | ||||
|     state.intermediate_mix_buffer[0] = input[0]; | ||||
| 
 | ||||
|  | @ -184,7 +194,8 @@ void Mixers::MixCurrentFrame() { | |||
|     current_frame.fill({}); | ||||
| 
 | ||||
|     for (size_t mix = 0; mix < 3; mix++) { | ||||
|         DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix], state.intermediate_mix_buffer[mix]); | ||||
|         DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix], | ||||
|                                       state.intermediate_mix_buffer[mix]); | ||||
|     } | ||||
| 
 | ||||
|     // TODO(merry): Compressor. (We currently assume a disabled compressor.)
 | ||||
|  |  | |||
|  | @ -20,10 +20,8 @@ public: | |||
| 
 | ||||
|     void Reset(); | ||||
| 
 | ||||
|     DspStatus Tick(DspConfiguration& config, | ||||
|                    const IntermediateMixSamples& read_samples, | ||||
|                    IntermediateMixSamples& write_samples, | ||||
|                    const std::array<QuadFrame32, 3>& input); | ||||
|     DspStatus Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples, | ||||
|                    IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input); | ||||
| 
 | ||||
|     StereoFrame16 GetOutput() const { | ||||
|         return current_frame; | ||||
|  | @ -53,7 +51,8 @@ private: | |||
|     void AuxSend(IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input); | ||||
|     /// INTERNAL: Mix current_frame.
 | ||||
|     void MixCurrentFrame(); | ||||
|     /// INTERNAL: Downmix from quadraphonic to stereo based on status.output_format and accumulate into current_frame.
 | ||||
|     /// INTERNAL: Downmix from quadraphonic to stereo based on status.output_format and accumulate
 | ||||
|     /// into current_frame.
 | ||||
|     void DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples); | ||||
|     /// INTERNAL: Generate DspStatus based on internal state.
 | ||||
|     DspStatus GetCurrentStatus() const; | ||||
|  |  | |||
|  | @ -44,8 +44,10 @@ std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) { | |||
|     std::vector<u8>& data = pipe_data[pipe_index]; | ||||
| 
 | ||||
|     if (length > data.size()) { | ||||
|         LOG_WARNING(Audio_DSP, "pipe_number = %zu is out of data, application requested read of %u but %zu remain", | ||||
|                     pipe_index, length, data.size()); | ||||
|         LOG_WARNING( | ||||
|             Audio_DSP, | ||||
|             "pipe_number = %zu is out of data, application requested read of %u but %zu remain", | ||||
|             pipe_index, length, data.size()); | ||||
|         length = static_cast<u32>(data.size()); | ||||
|     } | ||||
| 
 | ||||
|  | @ -95,8 +97,7 @@ static void AudioPipeWriteStructAddresses() { | |||
|         0x8000 + offsetof(SharedMemory, unknown11) / 2, | ||||
|         0x8000 + offsetof(SharedMemory, unknown12) / 2, | ||||
|         0x8000 + offsetof(SharedMemory, unknown13) / 2, | ||||
|         0x8000 + offsetof(SharedMemory, unknown14) / 2 | ||||
|     }; | ||||
|         0x8000 + offsetof(SharedMemory, unknown14) / 2}; | ||||
| 
 | ||||
|     // Begin with a u16 denoting the number of structs.
 | ||||
|     WriteU16(DspPipe::Audio, static_cast<u16>(struct_addresses.size())); | ||||
|  | @ -112,16 +113,12 @@ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) { | |||
|     switch (pipe_number) { | ||||
|     case DspPipe::Audio: { | ||||
|         if (buffer.size() != 4) { | ||||
|             LOG_ERROR(Audio_DSP, "DspPipe::Audio: Unexpected buffer length %zu was written", buffer.size()); | ||||
|             LOG_ERROR(Audio_DSP, "DspPipe::Audio: Unexpected buffer length %zu was written", | ||||
|                       buffer.size()); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         enum class StateChange { | ||||
|             Initalize = 0, | ||||
|             Shutdown = 1, | ||||
|             Wakeup = 2, | ||||
|             Sleep = 3 | ||||
|         }; | ||||
|         enum class StateChange { Initalize = 0, Shutdown = 1, Wakeup = 2, Sleep = 3 }; | ||||
| 
 | ||||
|         // The difference between Initialize and Wakeup is that Input state is maintained
 | ||||
|         // when sleeping but isn't when turning it off and on again. (TODO: Implement this.)
 | ||||
|  | @ -152,7 +149,9 @@ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) { | |||
|             dsp_state = DspState::Sleeping; | ||||
|             break; | ||||
|         default: | ||||
|             LOG_ERROR(Audio_DSP, "Application has requested unknown state transition of DSP hardware %hhu", buffer[0]); | ||||
|             LOG_ERROR(Audio_DSP, | ||||
|                       "Application has requested unknown state transition of DSP hardware %hhu", | ||||
|                       buffer[0]); | ||||
|             dsp_state = DspState::Off; | ||||
|             break; | ||||
|         } | ||||
|  | @ -160,7 +159,8 @@ void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) { | |||
|         return; | ||||
|     } | ||||
|     default: | ||||
|         LOG_CRITICAL(Audio_DSP, "pipe_number = %zu unimplemented", static_cast<size_t>(pipe_number)); | ||||
|         LOG_CRITICAL(Audio_DSP, "pipe_number = %zu unimplemented", | ||||
|                      static_cast<size_t>(pipe_number)); | ||||
|         UNIMPLEMENTED(); | ||||
|         return; | ||||
|     } | ||||
|  |  | |||
|  | @ -15,20 +15,17 @@ namespace HLE { | |||
| /// Reset the pipes by setting pipe positions back to the beginning.
 | ||||
| void ResetPipes(); | ||||
| 
 | ||||
| enum class DspPipe { | ||||
|     Debug = 0, | ||||
|     Dma = 1, | ||||
|     Audio = 2, | ||||
|     Binary = 3 | ||||
| }; | ||||
| enum class DspPipe { Debug = 0, Dma = 1, Audio = 2, Binary = 3 }; | ||||
| constexpr size_t NUM_DSP_PIPE = 8; | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads `length` bytes from the DSP pipe identified with `pipe_number`. | ||||
|  * @note Can read up to the maximum value of a u16 in bytes (65,535). | ||||
|  * @note IF an error is encoutered with either an invalid `pipe_number` or `length` value, an empty vector will be returned. | ||||
|  * @note IF an error is encoutered with either an invalid `pipe_number` or `length` value, an empty | ||||
|  * vector will be returned. | ||||
|  * @note IF `length` is set to 0, an empty vector will be returned. | ||||
|  * @note IF `length` is greater than the amount of data available, this function will only read the available amount. | ||||
|  * @note IF `length` is greater than the amount of data available, this function will only read the | ||||
|  * available amount. | ||||
|  * @param pipe_number a `DspPipe` | ||||
|  * @param length the number of bytes to read. The max is 65,535 (max of u16). | ||||
|  * @returns a vector of bytes from the specified pipe. On error, will be empty. | ||||
|  | @ -49,11 +46,7 @@ size_t GetPipeReadableSize(DspPipe pipe_number); | |||
|  */ | ||||
| void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer); | ||||
| 
 | ||||
| enum class DspState { | ||||
|     Off, | ||||
|     On, | ||||
|     Sleeping | ||||
| }; | ||||
| enum class DspState { Off, On, Sleeping }; | ||||
| /// Get the state of the DSP
 | ||||
| DspState GetDspState(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,7 +18,8 @@ | |||
| namespace DSP { | ||||
| namespace HLE { | ||||
| 
 | ||||
| SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) { | ||||
| SourceStatus::Status Source::Tick(SourceConfiguration::Configuration& config, | ||||
|                                   const s16_le (&adpcm_coeffs)[16]) { | ||||
|     ParseConfig(config, adpcm_coeffs); | ||||
| 
 | ||||
|     if (state.enabled) { | ||||
|  | @ -47,7 +48,8 @@ void Source::Reset() { | |||
|     state = {}; | ||||
| } | ||||
| 
 | ||||
| void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]) { | ||||
| void Source::ParseConfig(SourceConfiguration::Configuration& config, | ||||
|                          const s16_le (&adpcm_coeffs)[16]) { | ||||
|     if (!config.dirty_raw) { | ||||
|         return; | ||||
|     } | ||||
|  | @ -82,7 +84,8 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l | |||
|         LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", source_id, state.rate_multiplier); | ||||
| 
 | ||||
|         if (state.rate_multiplier <= 0) { | ||||
|             LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f", source_id, state.rate_multiplier); | ||||
|             LOG_ERROR(Audio_DSP, "Was given an invalid rate multiplier: source_id=%zu rate=%f", | ||||
|                       source_id, state.rate_multiplier); | ||||
|             state.rate_multiplier = 1.0f; | ||||
|             // Note: Actual firmware starts producing garbage if this occurs.
 | ||||
|         } | ||||
|  | @ -90,37 +93,39 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l | |||
| 
 | ||||
|     if (config.adpcm_coefficients_dirty) { | ||||
|         config.adpcm_coefficients_dirty.Assign(0); | ||||
|         std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(), state.adpcm_coeffs.begin(), | ||||
|             [](const auto& coeff) { return static_cast<s16>(coeff); }); | ||||
|         std::transform(adpcm_coeffs, adpcm_coeffs + state.adpcm_coeffs.size(), | ||||
|                        state.adpcm_coeffs.begin(), | ||||
|                        [](const auto& coeff) { return static_cast<s16>(coeff); }); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", source_id); | ||||
|     } | ||||
| 
 | ||||
|     if (config.gain_0_dirty) { | ||||
|         config.gain_0_dirty.Assign(0); | ||||
|         std::transform(config.gain[0], config.gain[0] + state.gain[0].size(), state.gain[0].begin(), | ||||
|             [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|                        [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu gain 0 update", source_id); | ||||
|     } | ||||
| 
 | ||||
|     if (config.gain_1_dirty) { | ||||
|         config.gain_1_dirty.Assign(0); | ||||
|         std::transform(config.gain[1], config.gain[1] + state.gain[1].size(), state.gain[1].begin(), | ||||
|             [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|                        [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu gain 1 update", source_id); | ||||
|     } | ||||
| 
 | ||||
|     if (config.gain_2_dirty) { | ||||
|         config.gain_2_dirty.Assign(0); | ||||
|         std::transform(config.gain[2], config.gain[2] + state.gain[2].size(), state.gain[2].begin(), | ||||
|             [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|                        [](const auto& coeff) { return static_cast<float>(coeff); }); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu gain 2 update", source_id); | ||||
|     } | ||||
| 
 | ||||
|     if (config.filters_enabled_dirty) { | ||||
|         config.filters_enabled_dirty.Assign(0); | ||||
|         state.filters.Enable(config.simple_filter_enabled.ToBool(), config.biquad_filter_enabled.ToBool()); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu", | ||||
|                   source_id, config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value()); | ||||
|         state.filters.Enable(config.simple_filter_enabled.ToBool(), | ||||
|                              config.biquad_filter_enabled.ToBool()); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu enable_simple=%hu enable_biquad=%hu", source_id, | ||||
|                   config.simple_filter_enabled.Value(), config.biquad_filter_enabled.Value()); | ||||
|     } | ||||
| 
 | ||||
|     if (config.simple_filter_dirty) { | ||||
|  | @ -138,36 +143,38 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l | |||
|     if (config.interpolation_dirty) { | ||||
|         config.interpolation_dirty.Assign(0); | ||||
|         state.interpolation_mode = config.interpolation_mode; | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id, static_cast<size_t>(state.interpolation_mode)); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu interpolation_mode=%zu", source_id, | ||||
|                   static_cast<size_t>(state.interpolation_mode)); | ||||
|     } | ||||
| 
 | ||||
|     if (config.format_dirty || config.embedded_buffer_dirty) { | ||||
|         config.format_dirty.Assign(0); | ||||
|         state.format = config.format; | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id, static_cast<size_t>(state.format)); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu format=%zu", source_id, | ||||
|                   static_cast<size_t>(state.format)); | ||||
|     } | ||||
| 
 | ||||
|     if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) { | ||||
|         config.mono_or_stereo_dirty.Assign(0); | ||||
|         state.mono_or_stereo = config.mono_or_stereo; | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id, static_cast<size_t>(state.mono_or_stereo)); | ||||
|         LOG_TRACE(Audio_DSP, "source_id=%zu mono_or_stereo=%zu", source_id, | ||||
|                   static_cast<size_t>(state.mono_or_stereo)); | ||||
|     } | ||||
| 
 | ||||
|     if (config.embedded_buffer_dirty) { | ||||
|         config.embedded_buffer_dirty.Assign(0); | ||||
|         state.input_queue.emplace(Buffer{ | ||||
|             config.physical_address, | ||||
|             config.length, | ||||
|             static_cast<u8>(config.adpcm_ps), | ||||
|             { config.adpcm_yn[0], config.adpcm_yn[1] }, | ||||
|             config.adpcm_dirty.ToBool(), | ||||
|             config.is_looping.ToBool(), | ||||
|             config.buffer_id, | ||||
|             state.mono_or_stereo, | ||||
|             state.format, | ||||
|             false | ||||
|         }); | ||||
|         LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu", config.physical_address, config.length, config.buffer_id); | ||||
|         state.input_queue.emplace(Buffer{config.physical_address, | ||||
|                                          config.length, | ||||
|                                          static_cast<u8>(config.adpcm_ps), | ||||
|                                          {config.adpcm_yn[0], config.adpcm_yn[1]}, | ||||
|                                          config.adpcm_dirty.ToBool(), | ||||
|                                          config.is_looping.ToBool(), | ||||
|                                          config.buffer_id, | ||||
|                                          state.mono_or_stereo, | ||||
|                                          state.format, | ||||
|                                          false}); | ||||
|         LOG_TRACE(Audio_DSP, "enqueuing embedded addr=0x%08x len=%u id=%hu", | ||||
|                   config.physical_address, config.length, config.buffer_id); | ||||
|     } | ||||
| 
 | ||||
|     if (config.buffer_queue_dirty) { | ||||
|  | @ -175,19 +182,18 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config, const s16_l | |||
|         for (size_t i = 0; i < 4; i++) { | ||||
|             if (config.buffers_dirty & (1 << i)) { | ||||
|                 const auto& b = config.buffers[i]; | ||||
|                 state.input_queue.emplace(Buffer{ | ||||
|                     b.physical_address, | ||||
|                     b.length, | ||||
|                     static_cast<u8>(b.adpcm_ps), | ||||
|                     { b.adpcm_yn[0], b.adpcm_yn[1] }, | ||||
|                     b.adpcm_dirty != 0, | ||||
|                     b.is_looping != 0, | ||||
|                     b.buffer_id, | ||||
|                     state.mono_or_stereo, | ||||
|                     state.format, | ||||
|                     true | ||||
|                 }); | ||||
|                 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i, b.physical_address, b.length, b.buffer_id); | ||||
|                 state.input_queue.emplace(Buffer{b.physical_address, | ||||
|                                                  b.length, | ||||
|                                                  static_cast<u8>(b.adpcm_ps), | ||||
|                                                  {b.adpcm_yn[0], b.adpcm_yn[1]}, | ||||
|                                                  b.adpcm_dirty != 0, | ||||
|                                                  b.is_looping != 0, | ||||
|                                                  b.buffer_id, | ||||
|                                                  state.mono_or_stereo, | ||||
|                                                  state.format, | ||||
|                                                  true}); | ||||
|                 LOG_TRACE(Audio_DSP, "enqueuing queued %zu addr=0x%08x len=%u id=%hu", i, | ||||
|                           b.physical_address, b.length, b.buffer_id); | ||||
|             } | ||||
|         } | ||||
|         config.buffers_dirty = 0; | ||||
|  | @ -218,10 +224,13 @@ void Source::GenerateFrame() { | |||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         const size_t size_to_copy = std::min(state.current_buffer.size(), current_frame.size() - frame_position); | ||||
|         const size_t size_to_copy = | ||||
|             std::min(state.current_buffer.size(), current_frame.size() - frame_position); | ||||
| 
 | ||||
|         std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy, current_frame.begin() + frame_position); | ||||
|         state.current_buffer.erase(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy); | ||||
|         std::copy(state.current_buffer.begin(), state.current_buffer.begin() + size_to_copy, | ||||
|                   current_frame.begin() + frame_position); | ||||
|         state.current_buffer.erase(state.current_buffer.begin(), | ||||
|                                    state.current_buffer.begin() + size_to_copy); | ||||
| 
 | ||||
|         frame_position += size_to_copy; | ||||
|         state.next_sample_number += static_cast<u32>(size_to_copy); | ||||
|  | @ -230,9 +239,9 @@ void Source::GenerateFrame() { | |||
|     state.filters.ProcessFrame(current_frame); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool Source::DequeueBuffer() { | ||||
|     ASSERT_MSG(state.current_buffer.empty(), "Shouldn't dequeue; we still have data in current_buffer"); | ||||
|     ASSERT_MSG(state.current_buffer.empty(), | ||||
|                "Shouldn't dequeue; we still have data in current_buffer"); | ||||
| 
 | ||||
|     if (state.input_queue.empty()) | ||||
|         return false; | ||||
|  | @ -261,29 +270,34 @@ bool Source::DequeueBuffer() { | |||
|             break; | ||||
|         case Format::ADPCM: | ||||
|             DEBUG_ASSERT(num_channels == 1); | ||||
|             state.current_buffer = Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state); | ||||
|             state.current_buffer = | ||||
|                 Codec::DecodeADPCM(memory, buf.length, state.adpcm_coeffs, state.adpcm_state); | ||||
|             break; | ||||
|         default: | ||||
|             UNIMPLEMENTED(); | ||||
|             break; | ||||
|         } | ||||
|     } else { | ||||
|         LOG_WARNING(Audio_DSP, "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X", | ||||
|                                source_id, buf.buffer_id, buf.length, buf.physical_address); | ||||
|         LOG_WARNING(Audio_DSP, | ||||
|                     "source_id=%zu buffer_id=%hu length=%u: Invalid physical address 0x%08X", | ||||
|                     source_id, buf.buffer_id, buf.length, buf.physical_address); | ||||
|         state.current_buffer.clear(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     switch (state.interpolation_mode) { | ||||
|     case InterpolationMode::None: | ||||
|         state.current_buffer = AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         state.current_buffer = | ||||
|             AudioInterp::None(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         break; | ||||
|     case InterpolationMode::Linear: | ||||
|         state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         state.current_buffer = | ||||
|             AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         break; | ||||
|     case InterpolationMode::Polyphase: | ||||
|         // TODO(merry): Implement polyphase interpolation
 | ||||
|         state.current_buffer = AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         state.current_buffer = | ||||
|             AudioInterp::Linear(state.interp_state, state.current_buffer, state.rate_multiplier); | ||||
|         break; | ||||
|     default: | ||||
|         UNIMPLEMENTED(); | ||||
|  | @ -296,7 +310,8 @@ bool Source::DequeueBuffer() { | |||
|     state.buffer_update = buf.from_queue; | ||||
| 
 | ||||
|     LOG_TRACE(Audio_DSP, "source_id=%zu buffer_id=%hu from_queue=%s current_buffer.size()=%zu", | ||||
|                          source_id, buf.buffer_id, buf.from_queue ? "true" : "false", state.current_buffer.size()); | ||||
|               source_id, buf.buffer_id, buf.from_queue ? "true" : "false", | ||||
|               state.current_buffer.size()); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -40,13 +40,17 @@ public: | |||
|     /**
 | ||||
|      * This is called once every audio frame. This performs per-source processing every frame. | ||||
|      * @param config The new configuration we've got for this Source from the application. | ||||
|      * @param adpcm_coeffs ADPCM coefficients to use if config tells us to use them (may contain invalid values otherwise). | ||||
|      * @return The current status of this Source. This is given back to the emulated application via SharedMemory. | ||||
|      * @param adpcm_coeffs ADPCM coefficients to use if config tells us to use them (may contain | ||||
|      * invalid values otherwise). | ||||
|      * @return The current status of this Source. This is given back to the emulated application via | ||||
|      * SharedMemory. | ||||
|      */ | ||||
|     SourceStatus::Status Tick(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]); | ||||
|     SourceStatus::Status Tick(SourceConfiguration::Configuration& config, | ||||
|                               const s16_le (&adpcm_coeffs)[16]); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Mix this source's output into dest, using the gains for the `intermediate_mix_id`-th intermediate mixer. | ||||
|      * Mix this source's output into dest, using the gains for the `intermediate_mix_id`-th | ||||
|      * intermediate mixer. | ||||
|      * @param dest The QuadFrame32 to mix into. | ||||
|      * @param intermediate_mix_id The id of the intermediate mix whose gains we are using. | ||||
|      */ | ||||
|  | @ -77,7 +81,7 @@ private: | |||
|     }; | ||||
| 
 | ||||
|     struct BufferOrder { | ||||
|         bool operator() (const Buffer& a, const Buffer& b) const { | ||||
|         bool operator()(const Buffer& a, const Buffer& b) const { | ||||
|             // Lower buffer_id comes first.
 | ||||
|             return a.buffer_id > b.buffer_id; | ||||
|         } | ||||
|  | @ -134,7 +138,8 @@ private: | |||
|     void ParseConfig(SourceConfiguration::Configuration& config, const s16_le (&adpcm_coeffs)[16]); | ||||
|     /// INTERNAL: Generate the current audio output for this frame based on our internal state.
 | ||||
|     void GenerateFrame(); | ||||
|     /// INTERNAL: Dequeues a buffer and does preprocessing on it (decoding, resampling). Puts it into current_buffer.
 | ||||
|     /// INTERNAL: Dequeues a buffer and does preprocessing on it (decoding, resampling). Puts it
 | ||||
|     /// into current_buffer.
 | ||||
|     bool DequeueBuffer(); | ||||
|     /// INTERNAL: Generates a SourceStatus::Status based on our internal state.
 | ||||
|     SourceStatus::Status GetCurrentStatus(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue