mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #4932 from ogniK5377/misc-audio
audren: Make use of nodiscard, rework downmixing, release all buffers
This commit is contained in:
		
						commit
						b7f1095980
					
				| @ -43,6 +43,10 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, | |||||||
|     return stream->GetTagsAndReleaseBuffers(max_count); |     return stream->GetTagsAndReleaseBuffers(max_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) { | ||||||
|  |     return stream->GetTagsAndReleaseBuffers(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AudioOut::StartStream(StreamPtr stream) { | void AudioOut::StartStream(StreamPtr stream) { | ||||||
|     stream->Play(); |     stream->Play(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,6 +31,9 @@ public: | |||||||
|     /// Returns a vector of recently released buffers specified by tag for the specified stream
 |     /// Returns a vector of recently released buffers specified by tag for the specified stream
 | ||||||
|     std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); |     std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); | ||||||
| 
 | 
 | ||||||
|  |     /// Returns a vector of all recently released buffers specified by tag for the specified stream
 | ||||||
|  |     std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream); | ||||||
|  | 
 | ||||||
|     /// Starts an audio stream for playback
 |     /// Starts an audio stream for playback
 | ||||||
|     void StartStream(StreamPtr stream); |     void StartStream(StreamPtr stream); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
|  | #include <limits> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| #include "audio_core/audio_out.h" | #include "audio_core/audio_out.h" | ||||||
| @ -14,6 +15,59 @@ | |||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| 
 | 
 | ||||||
|  | namespace { | ||||||
|  | [[nodiscard]] static constexpr s16 ClampToS16(s32 value) { | ||||||
|  |     return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()}, | ||||||
|  |                                        s32{std::numeric_limits<s16>::max()})); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) { | ||||||
|  |     // Mix 50% from left and 50% from right channel
 | ||||||
|  |     constexpr float l_mix_amount = 50.0f / 100.0f; | ||||||
|  |     constexpr float r_mix_amount = 50.0f / 100.0f; | ||||||
|  |     return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) + | ||||||
|  |                                        (static_cast<float>(r_channel) * r_mix_amount))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel, | ||||||
|  |                                                             s16 fc_channel, | ||||||
|  |                                                             [[maybe_unused]] s16 lf_channel, | ||||||
|  |                                                             s16 bl_channel, s16 br_channel) { | ||||||
|  |     // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
 | ||||||
|  |     // are mixed to be 36.94%
 | ||||||
|  | 
 | ||||||
|  |     constexpr float front_mix_amount = 36.94f / 100.0f; | ||||||
|  |     constexpr float center_mix_amount = 26.12f / 100.0f; | ||||||
|  |     constexpr float back_mix_amount = 36.94f / 100.0f; | ||||||
|  | 
 | ||||||
|  |     // Mix 50% from left and 50% from right channel
 | ||||||
|  |     const auto left = front_mix_amount * static_cast<float>(fl_channel) + | ||||||
|  |                       center_mix_amount * static_cast<float>(fc_channel) + | ||||||
|  |                       back_mix_amount * static_cast<float>(bl_channel); | ||||||
|  | 
 | ||||||
|  |     const auto right = front_mix_amount * static_cast<float>(fr_channel) + | ||||||
|  |                        center_mix_amount * static_cast<float>(fc_channel) + | ||||||
|  |                        back_mix_amount * static_cast<float>(br_channel); | ||||||
|  | 
 | ||||||
|  |     return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients( | ||||||
|  |     s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel, | ||||||
|  |     const std::array<float_le, 4>& coeff) { | ||||||
|  |     const auto left = | ||||||
|  |         static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + | ||||||
|  |         static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0]; | ||||||
|  | 
 | ||||||
|  |     const auto right = | ||||||
|  |         static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + | ||||||
|  |         static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0]; | ||||||
|  | 
 | ||||||
|  |     return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
| namespace AudioCore { | namespace AudioCore { | ||||||
| AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | ||||||
|                              AudioCommon::AudioRendererParameter params, |                              AudioCommon::AudioRendererParameter params, | ||||||
| @ -62,10 +116,6 @@ Stream::State AudioRenderer::GetStreamState() const { | |||||||
|     return stream->GetState(); |     return stream->GetState(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static constexpr s16 ClampToS16(s32 value) { |  | ||||||
|     return static_cast<s16>(std::clamp(value, -32768, 32767)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, | ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, | ||||||
|                                               std::vector<u8>& output_params) { |                                               std::vector<u8>& output_params) { | ||||||
| 
 | 
 | ||||||
| @ -104,7 +154,7 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, |     const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, | ||||||
|                                                      splitter_context, effect_context); |                                                      splitter_context, effect_context); | ||||||
| 
 | 
 | ||||||
|     if (mix_result.IsError()) { |     if (mix_result.IsError()) { | ||||||
| @ -194,20 +244,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||||||
|         for (std::size_t i = 0; i < BUFFER_SIZE; i++) { |         for (std::size_t i = 0; i < BUFFER_SIZE; i++) { | ||||||
|             if (channel_count == 1) { |             if (channel_count == 1) { | ||||||
|                 const auto sample = ClampToS16(mix_buffers[0][i]); |                 const auto sample = ClampToS16(mix_buffers[0][i]); | ||||||
|                 buffer[i * stream_channel_count + 0] = sample; | 
 | ||||||
|                 if (stream_channel_count > 1) { |                 // Place sample in all channels
 | ||||||
|                     buffer[i * stream_channel_count + 1] = sample; |                 for (u32 channel = 0; channel < stream_channel_count; channel++) { | ||||||
|  |                     buffer[i * stream_channel_count + channel] = sample; | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 if (stream_channel_count == 6) { |                 if (stream_channel_count == 6) { | ||||||
|                     buffer[i * stream_channel_count + 2] = sample; |                     // Output stream has a LF channel, mute it!
 | ||||||
|                     buffer[i * stream_channel_count + 4] = sample; |                     buffer[i * stream_channel_count + 3] = 0; | ||||||
|                     buffer[i * stream_channel_count + 5] = sample; |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|             } else if (channel_count == 2) { |             } else if (channel_count == 2) { | ||||||
|                 const auto l_sample = ClampToS16(mix_buffers[0][i]); |                 const auto l_sample = ClampToS16(mix_buffers[0][i]); | ||||||
|                 const auto r_sample = ClampToS16(mix_buffers[1][i]); |                 const auto r_sample = ClampToS16(mix_buffers[1][i]); | ||||||
|                 if (stream_channel_count == 1) { |                 if (stream_channel_count == 1) { | ||||||
|                     buffer[i * stream_channel_count + 0] = l_sample; |                     buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample); | ||||||
|                 } else if (stream_channel_count == 2) { |                 } else if (stream_channel_count == 2) { | ||||||
|                     buffer[i * stream_channel_count + 0] = l_sample; |                     buffer[i * stream_channel_count + 0] = l_sample; | ||||||
|                     buffer[i * stream_channel_count + 1] = r_sample; |                     buffer[i * stream_channel_count + 1] = r_sample; | ||||||
| @ -215,8 +267,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||||||
|                     buffer[i * stream_channel_count + 0] = l_sample; |                     buffer[i * stream_channel_count + 0] = l_sample; | ||||||
|                     buffer[i * stream_channel_count + 1] = r_sample; |                     buffer[i * stream_channel_count + 1] = r_sample; | ||||||
| 
 | 
 | ||||||
|                     buffer[i * stream_channel_count + 2] = |                     // Combine both left and right channels to the center channel
 | ||||||
|                         ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); |                     buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample); | ||||||
| 
 | 
 | ||||||
|                     buffer[i * stream_channel_count + 4] = l_sample; |                     buffer[i * stream_channel_count + 4] = l_sample; | ||||||
|                     buffer[i * stream_channel_count + 5] = r_sample; |                     buffer[i * stream_channel_count + 5] = r_sample; | ||||||
| @ -231,17 +283,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||||||
|                 const auto br_sample = ClampToS16(mix_buffers[5][i]); |                 const auto br_sample = ClampToS16(mix_buffers[5][i]); | ||||||
| 
 | 
 | ||||||
|                 if (stream_channel_count == 1) { |                 if (stream_channel_count == 1) { | ||||||
|                     buffer[i * stream_channel_count + 0] = fc_sample; |                     // Games seem to ignore the center channel half the time, we use the front left
 | ||||||
|  |                     // and right channel for mixing as that's where majority of the audio goes
 | ||||||
|  |                     buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample); | ||||||
|                 } else if (stream_channel_count == 2) { |                 } else if (stream_channel_count == 2) { | ||||||
|                     buffer[i * stream_channel_count + 0] = |                     // Mix all channels into 2 channels
 | ||||||
|                         static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + |                     if (sink_context.HasDownMixingCoefficients()) { | ||||||
|                                          0.2612f * static_cast<float>(fc_sample) + |                         const auto [left, right] = Mix6To2WithCoefficients( | ||||||
|                                          0.3694f * static_cast<float>(bl_sample)); |                             fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample, | ||||||
|                     buffer[i * stream_channel_count + 1] = |                             sink_context.GetDownmixCoefficients()); | ||||||
|                         static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + |                         buffer[i * stream_channel_count + 0] = left; | ||||||
|                                          0.2612f * static_cast<float>(fc_sample) + |                         buffer[i * stream_channel_count + 1] = right; | ||||||
|                                          0.3694f * static_cast<float>(br_sample)); |                     } else { | ||||||
|  |                         const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample, | ||||||
|  |                                                            lf_sample, bl_sample, br_sample); | ||||||
|  |                         buffer[i * stream_channel_count + 0] = left; | ||||||
|  |                         buffer[i * stream_channel_count + 1] = right; | ||||||
|  |                     } | ||||||
|                 } else if (stream_channel_count == 6) { |                 } else if (stream_channel_count == 6) { | ||||||
|  |                     // Pass through
 | ||||||
|                     buffer[i * stream_channel_count + 0] = fl_sample; |                     buffer[i * stream_channel_count + 0] = fl_sample; | ||||||
|                     buffer[i * stream_channel_count + 1] = fr_sample; |                     buffer[i * stream_channel_count + 1] = fr_sample; | ||||||
|                     buffer[i * stream_channel_count + 2] = fc_sample; |                     buffer[i * stream_channel_count + 2] = fc_sample; | ||||||
| @ -259,7 +319,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AudioRenderer::ReleaseAndQueueBuffers() { | void AudioRenderer::ReleaseAndQueueBuffers() { | ||||||
|     const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; |     const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)}; | ||||||
|     for (const auto& tag : released_buffers) { |     for (const auto& tag : released_buffers) { | ||||||
|         QueueMixedBuffer(tag); |         QueueMixedBuffer(tag); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -36,16 +36,10 @@ class Memory; | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace AudioCore { | namespace AudioCore { | ||||||
| using DSPStateHolder = std::array<VoiceState*, 6>; | using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>; | ||||||
| 
 | 
 | ||||||
| class AudioOut; | class AudioOut; | ||||||
| 
 | 
 | ||||||
| struct RendererInfo { |  | ||||||
|     u64_le elasped_frame_count{}; |  | ||||||
|     INSERT_PADDING_WORDS(2); |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size"); |  | ||||||
| 
 |  | ||||||
| class AudioRenderer { | class AudioRenderer { | ||||||
| public: | public: | ||||||
|     AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, |     AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | ||||||
| @ -53,14 +47,14 @@ public: | |||||||
|                   std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); |                   std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); | ||||||
|     ~AudioRenderer(); |     ~AudioRenderer(); | ||||||
| 
 | 
 | ||||||
|     ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, |     [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, | ||||||
|                                                  std::vector<u8>& output_params); |                                                  std::vector<u8>& output_params); | ||||||
|     void QueueMixedBuffer(Buffer::Tag tag); |     void QueueMixedBuffer(Buffer::Tag tag); | ||||||
|     void ReleaseAndQueueBuffers(); |     void ReleaseAndQueueBuffers(); | ||||||
|     u32 GetSampleRate() const; |     [[nodiscard]] u32 GetSampleRate() const; | ||||||
|     u32 GetSampleCount() const; |     [[nodiscard]] u32 GetSampleCount() const; | ||||||
|     u32 GetMixBufferCount() const; |     [[nodiscard]] u32 GetMixBufferCount() const; | ||||||
|     Stream::State GetStreamState() const; |     [[nodiscard]] Stream::State GetStreamState() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     BehaviorInfo behavior_info{}; |     BehaviorInfo behavior_info{}; | ||||||
|  | |||||||
| @ -43,22 +43,22 @@ public: | |||||||
|     void ClearError(); |     void ClearError(); | ||||||
|     void UpdateFlags(u64_le dest_flags); |     void UpdateFlags(u64_le dest_flags); | ||||||
|     void SetUserRevision(u32_le revision); |     void SetUserRevision(u32_le revision); | ||||||
|     u32_le GetUserRevision() const; |     [[nodiscard]] u32_le GetUserRevision() const; | ||||||
|     u32_le GetProcessRevision() const; |     [[nodiscard]] u32_le GetProcessRevision() const; | ||||||
| 
 | 
 | ||||||
|     bool IsAdpcmLoopContextBugFixed() const; |     [[nodiscard]] bool IsAdpcmLoopContextBugFixed() const; | ||||||
|     bool IsSplitterSupported() const; |     [[nodiscard]] bool IsSplitterSupported() const; | ||||||
|     bool IsLongSizePreDelaySupported() const; |     [[nodiscard]] bool IsLongSizePreDelaySupported() const; | ||||||
|     bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; |     [[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; | ||||||
|     bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; |     [[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; | ||||||
|     bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; |     [[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; | ||||||
|     bool IsElapsedFrameCountSupported() const; |     [[nodiscard]] bool IsElapsedFrameCountSupported() const; | ||||||
|     bool IsMemoryPoolForceMappingEnabled() const; |     [[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const; | ||||||
|     bool IsFlushVoiceWaveBuffersSupported() const; |     [[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const; | ||||||
|     bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; |     [[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; | ||||||
|     bool IsVoicePitchAndSrcSkippedSupported() const; |     [[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const; | ||||||
|     bool IsMixInParameterDirtyOnlyUpdateSupported() const; |     [[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const; | ||||||
|     bool IsSplitterBugFixed() const; |     [[nodiscard]] bool IsSplitterBugFixed() const; | ||||||
|     void CopyErrorInfo(OutParams& dst); |     void CopyErrorInfo(OutParams& dst); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | |||||||
| @ -39,13 +39,13 @@ public: | |||||||
|     void PreCommand(); |     void PreCommand(); | ||||||
|     void PostCommand(); |     void PostCommand(); | ||||||
| 
 | 
 | ||||||
|     s32* GetChannelMixBuffer(s32 channel); |     [[nodiscard]] s32* GetChannelMixBuffer(s32 channel); | ||||||
|     const s32* GetChannelMixBuffer(s32 channel) const; |     [[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const; | ||||||
|     s32* GetMixBuffer(std::size_t index); |     [[nodiscard]] s32* GetMixBuffer(std::size_t index); | ||||||
|     const s32* GetMixBuffer(std::size_t index) const; |     [[nodiscard]] const s32* GetMixBuffer(std::size_t index) const; | ||||||
|     std::size_t GetMixChannelBufferOffset(s32 channel) const; |     [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const; | ||||||
| 
 | 
 | ||||||
|     std::size_t GetTotalMixBufferCount() const; |     [[nodiscard]] std::size_t GetTotalMixBufferCount() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); |     void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); | ||||||
| @ -73,7 +73,7 @@ private: | |||||||
|     void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |     void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | ||||||
|     void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |     void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | ||||||
|     void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |     void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | ||||||
|     ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); |     [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); | ||||||
| 
 | 
 | ||||||
|     s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, |     s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, | ||||||
|                        u32 sample_count, u32 write_offset, u32 write_count); |                        u32 sample_count, u32 write_offset, u32 write_count); | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6; | |||||||
| constexpr std::size_t MAX_WAVE_BUFFERS = 4; | constexpr std::size_t MAX_WAVE_BUFFERS = 4; | ||||||
| constexpr std::size_t MAX_SAMPLE_HISTORY = 4; | constexpr std::size_t MAX_SAMPLE_HISTORY = 4; | ||||||
| constexpr u32 STREAM_SAMPLE_RATE = 48000; | constexpr u32 STREAM_SAMPLE_RATE = 48000; | ||||||
| constexpr u32 STREAM_NUM_CHANNELS = 6; | constexpr u32 STREAM_NUM_CHANNELS = 2; | ||||||
| constexpr s32 NO_SPLITTER = -1; | constexpr s32 NO_SPLITTER = -1; | ||||||
| constexpr s32 NO_MIX = 0x7fffffff; | constexpr s32 NO_MIX = 0x7fffffff; | ||||||
| constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); | constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); | ||||||
|  | |||||||
| @ -189,11 +189,11 @@ public: | |||||||
| 
 | 
 | ||||||
|     virtual void Update(EffectInfo::InParams& in_params) = 0; |     virtual void Update(EffectInfo::InParams& in_params) = 0; | ||||||
|     virtual void UpdateForCommandGeneration() = 0; |     virtual void UpdateForCommandGeneration() = 0; | ||||||
|     UsageState GetUsage() const; |     [[nodiscard]] UsageState GetUsage() const; | ||||||
|     EffectType GetType() const; |     [[nodiscard]] EffectType GetType() const; | ||||||
|     bool IsEnabled() const; |     [[nodiscard]] bool IsEnabled() const; | ||||||
|     s32 GetMixID() const; |     [[nodiscard]] s32 GetMixID() const; | ||||||
|     s32 GetProcessingOrder() const; |     [[nodiscard]] s32 GetProcessingOrder() const; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     UsageState usage{UsageState::Invalid}; |     UsageState usage{UsageState::Invalid}; | ||||||
| @ -257,10 +257,10 @@ public: | |||||||
| 
 | 
 | ||||||
|     void Update(EffectInfo::InParams& in_params) override; |     void Update(EffectInfo::InParams& in_params) override; | ||||||
|     void UpdateForCommandGeneration() override; |     void UpdateForCommandGeneration() override; | ||||||
|     VAddr GetSendInfo() const; |     [[nodiscard]] VAddr GetSendInfo() const; | ||||||
|     VAddr GetSendBuffer() const; |     [[nodiscard]] VAddr GetSendBuffer() const; | ||||||
|     VAddr GetRecvInfo() const; |     [[nodiscard]] VAddr GetRecvInfo() const; | ||||||
|     VAddr GetRecvBuffer() const; |     [[nodiscard]] VAddr GetRecvBuffer() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     VAddr send_info{}; |     VAddr send_info{}; | ||||||
| @ -309,10 +309,10 @@ public: | |||||||
|     explicit EffectContext(std::size_t effect_count); |     explicit EffectContext(std::size_t effect_count); | ||||||
|     ~EffectContext(); |     ~EffectContext(); | ||||||
| 
 | 
 | ||||||
|     std::size_t GetCount() const; |     [[nodiscard]] std::size_t GetCount() const; | ||||||
|     EffectBase* GetInfo(std::size_t i); |     [[nodiscard]] EffectBase* GetInfo(std::size_t i); | ||||||
|     EffectBase* RetargetEffect(std::size_t i, EffectType effect); |     [[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect); | ||||||
|     const EffectBase* GetInfo(std::size_t i) const; |     [[nodiscard]] const EffectBase* GetInfo(std::size_t i) const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::size_t effect_count{}; |     std::size_t effect_count{}; | ||||||
|  | |||||||
| @ -62,17 +62,17 @@ public: | |||||||
|     ServerMixInfo(); |     ServerMixInfo(); | ||||||
|     ~ServerMixInfo(); |     ~ServerMixInfo(); | ||||||
| 
 | 
 | ||||||
|     const ServerMixInfo::InParams& GetInParams() const; |     [[nodiscard]] const ServerMixInfo::InParams& GetInParams() const; | ||||||
|     ServerMixInfo::InParams& GetInParams(); |     [[nodiscard]] ServerMixInfo::InParams& GetInParams(); | ||||||
| 
 | 
 | ||||||
|     bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, |     bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, | ||||||
|                 BehaviorInfo& behavior_info, SplitterContext& splitter_context, |                 BehaviorInfo& behavior_info, SplitterContext& splitter_context, | ||||||
|                 EffectContext& effect_context); |                 EffectContext& effect_context); | ||||||
|     bool HasAnyConnection() const; |     [[nodiscard]] bool HasAnyConnection() const; | ||||||
|     void Cleanup(); |     void Cleanup(); | ||||||
|     void SetEffectCount(std::size_t count); |     void SetEffectCount(std::size_t count); | ||||||
|     void ResetEffectProcessingOrder(); |     void ResetEffectProcessingOrder(); | ||||||
|     s32 GetEffectOrder(std::size_t i) const; |     [[nodiscard]] s32 GetEffectOrder(std::size_t i) const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::vector<s32> effect_processing_order; |     std::vector<s32> effect_processing_order; | ||||||
| @ -91,15 +91,15 @@ public: | |||||||
|     void SortInfo(); |     void SortInfo(); | ||||||
|     bool TsortInfo(SplitterContext& splitter_context); |     bool TsortInfo(SplitterContext& splitter_context); | ||||||
| 
 | 
 | ||||||
|     std::size_t GetCount() const; |     [[nodiscard]] std::size_t GetCount() const; | ||||||
|     ServerMixInfo& GetInfo(std::size_t i); |     [[nodiscard]] ServerMixInfo& GetInfo(std::size_t i); | ||||||
|     const ServerMixInfo& GetInfo(std::size_t i) const; |     [[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const; | ||||||
|     ServerMixInfo& GetSortedInfo(std::size_t i); |     [[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i); | ||||||
|     const ServerMixInfo& GetSortedInfo(std::size_t i) const; |     [[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const; | ||||||
|     ServerMixInfo& GetFinalMixInfo(); |     [[nodiscard]] ServerMixInfo& GetFinalMixInfo(); | ||||||
|     const ServerMixInfo& GetFinalMixInfo() const; |     [[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const; | ||||||
|     EdgeMatrix& GetEdgeMatrix(); |     [[nodiscard]] EdgeMatrix& GetEdgeMatrix(); | ||||||
|     const EdgeMatrix& GetEdgeMatrix() const; |     [[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void CalcMixBufferOffset(); |     void CalcMixBufferOffset(); | ||||||
|  | |||||||
| @ -12,10 +12,16 @@ std::size_t SinkContext::GetCount() const { | |||||||
|     return sink_count; |     return sink_count; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SinkContext::UpdateMainSink(SinkInfo::InParams& in) { | void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) { | ||||||
|  |     ASSERT(in.type == SinkTypes::Device); | ||||||
|  | 
 | ||||||
|  |     has_downmix_coefs = in.device.down_matrix_enabled; | ||||||
|  |     if (has_downmix_coefs) { | ||||||
|  |         downmix_coefficients = in.device.down_matrix_coef; | ||||||
|  |     } | ||||||
|     in_use = in.in_use; |     in_use = in.in_use; | ||||||
|     use_count = in.device.input_count; |     use_count = in.device.input_count; | ||||||
|     std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT); |     buffers = in.device.input; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool SinkContext::InUse() const { | bool SinkContext::InUse() const { | ||||||
| @ -28,4 +34,12 @@ std::vector<u8> SinkContext::OutputBuffers() const { | |||||||
|     return buffer_ret; |     return buffer_ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool SinkContext::HasDownMixingCoefficients() const { | ||||||
|  |     return has_downmix_coefs; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const { | ||||||
|  |     return downmix_coefficients; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace AudioCore
 | } // namespace AudioCore
 | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ | |||||||
| 
 | 
 | ||||||
| namespace AudioCore { | namespace AudioCore { | ||||||
| 
 | 
 | ||||||
|  | using DownmixCoefficients = std::array<float_le, 4>; | ||||||
|  | 
 | ||||||
| enum class SinkTypes : u8 { | enum class SinkTypes : u8 { | ||||||
|     Invalid = 0, |     Invalid = 0, | ||||||
|     Device = 1, |     Device = 1, | ||||||
| @ -50,7 +52,7 @@ public: | |||||||
|         std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; |         std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; | ||||||
|         INSERT_UNION_PADDING_BYTES(1); |         INSERT_UNION_PADDING_BYTES(1); | ||||||
|         bool down_matrix_enabled; |         bool down_matrix_enabled; | ||||||
|         std::array<float_le, 4> down_matrix_coef; |         DownmixCoefficients down_matrix_coef; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); |     static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); | ||||||
| 
 | 
 | ||||||
| @ -74,16 +76,21 @@ public: | |||||||
|     explicit SinkContext(std::size_t sink_count); |     explicit SinkContext(std::size_t sink_count); | ||||||
|     ~SinkContext(); |     ~SinkContext(); | ||||||
| 
 | 
 | ||||||
|     std::size_t GetCount() const; |     [[nodiscard]] std::size_t GetCount() const; | ||||||
| 
 | 
 | ||||||
|     void UpdateMainSink(SinkInfo::InParams& in); |     void UpdateMainSink(const SinkInfo::InParams& in); | ||||||
|     bool InUse() const; |     [[nodiscard]] bool InUse() const; | ||||||
|     std::vector<u8> OutputBuffers() const; |     [[nodiscard]] std::vector<u8> OutputBuffers() const; | ||||||
|  | 
 | ||||||
|  |     [[nodiscard]] bool HasDownMixingCoefficients() const; | ||||||
|  |     [[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     bool in_use{false}; |     bool in_use{false}; | ||||||
|     s32 use_count{}; |     s32 use_count{}; | ||||||
|     std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; |     std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; | ||||||
|     std::size_t sink_count{}; |     std::size_t sink_count{}; | ||||||
|  |     bool has_downmix_coefs{false}; | ||||||
|  |     DownmixCoefficients downmix_coefficients{}; | ||||||
| }; | }; | ||||||
| } // namespace AudioCore
 | } // namespace AudioCore
 | ||||||
|  | |||||||
| @ -136,4 +136,14 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) | |||||||
|     return tags; |     return tags; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() { | ||||||
|  |     std::vector<Buffer::Tag> tags; | ||||||
|  |     tags.reserve(released_buffers.size()); | ||||||
|  |     while (!released_buffers.empty()) { | ||||||
|  |         tags.push_back(released_buffers.front()->GetTag()); | ||||||
|  |         released_buffers.pop(); | ||||||
|  |     } | ||||||
|  |     return tags; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace AudioCore
 | } // namespace AudioCore
 | ||||||
|  | |||||||
| @ -57,37 +57,40 @@ public: | |||||||
|     bool QueueBuffer(BufferPtr&& buffer); |     bool QueueBuffer(BufferPtr&& buffer); | ||||||
| 
 | 
 | ||||||
|     /// Returns true if the audio stream contains a buffer with the specified tag
 |     /// Returns true if the audio stream contains a buffer with the specified tag
 | ||||||
|     bool ContainsBuffer(Buffer::Tag tag) const; |     [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const; | ||||||
| 
 | 
 | ||||||
|     /// Returns a vector of recently released buffers specified by tag
 |     /// Returns a vector of recently released buffers specified by tag
 | ||||||
|     std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); |     [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); | ||||||
|  | 
 | ||||||
|  |     /// Returns a vector of all recently released buffers specified by tag
 | ||||||
|  |     [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(); | ||||||
| 
 | 
 | ||||||
|     void SetVolume(float volume); |     void SetVolume(float volume); | ||||||
| 
 | 
 | ||||||
|     float GetVolume() const { |     [[nodiscard]] float GetVolume() const { | ||||||
|         return game_volume; |         return game_volume; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Returns true if the stream is currently playing
 |     /// Returns true if the stream is currently playing
 | ||||||
|     bool IsPlaying() const { |     [[nodiscard]] bool IsPlaying() const { | ||||||
|         return state == State::Playing; |         return state == State::Playing; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Returns the number of queued buffers
 |     /// Returns the number of queued buffers
 | ||||||
|     std::size_t GetQueueSize() const { |     [[nodiscard]] std::size_t GetQueueSize() const { | ||||||
|         return queued_buffers.size(); |         return queued_buffers.size(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Gets the sample rate
 |     /// Gets the sample rate
 | ||||||
|     u32 GetSampleRate() const { |     [[nodiscard]] u32 GetSampleRate() const { | ||||||
|         return sample_rate; |         return sample_rate; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Gets the number of channels
 |     /// Gets the number of channels
 | ||||||
|     u32 GetNumChannels() const; |     [[nodiscard]] u32 GetNumChannels() const; | ||||||
| 
 | 
 | ||||||
|     /// Get the state
 |     /// Get the state
 | ||||||
|     State GetState() const; |     [[nodiscard]] State GetState() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     /// Plays the next queued buffer in the audio stream, starting playback if necessary
 |     /// Plays the next queued buffer in the audio stream, starting playback if necessary
 | ||||||
| @ -97,7 +100,7 @@ private: | |||||||
|     void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); |     void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); | ||||||
| 
 | 
 | ||||||
|     /// Gets the number of core cycles when the specified buffer will be released
 |     /// Gets the number of core cycles when the specified buffer will be released
 | ||||||
|     std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; |     [[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; | ||||||
| 
 | 
 | ||||||
|     u32 sample_rate;                  ///< Sample rate of the stream
 |     u32 sample_rate;                  ///< Sample rate of the stream
 | ||||||
|     Format format;                    ///< Format of the stream
 |     Format format;                    ///< Format of the stream
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei