| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_MEDIA_AUDIO_LIB_PROCESSING_POSITION_MANAGER_H_ |
| #define SRC_MEDIA_AUDIO_LIB_PROCESSING_POSITION_MANAGER_H_ |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/media/audio/lib/format2/fixed.h" |
| |
| namespace media_audio { |
| |
| // Enable to emit trace events containing the position state. |
| // TODO(fxbug.dev/87651): Move this constant to a common location if needed during audio core |
| // `media::audio::Mixer` migration. |
| inline constexpr bool kTracePositionEvents = false; |
| |
| // Class that handles the updating of source and destination positions, as a resampler steps through |
| // source buffers with a specific step size (based on the resampling ratio). This class extracts a |
| // significant amount of duplicate code across the samplers. |
| class PositionManager { |
| public: |
| PositionManager(int32_t source_channel_count, int32_t dest_channel_count, int64_t positive_length, |
| int64_t negative_length); |
| ~PositionManager() = default; |
| |
| // Non-copyable and non-movable. |
| PositionManager(const PositionManager& other) = delete; |
| PositionManager& operator=(const PositionManager& other) = delete; |
| PositionManager(PositionManager&& other) = delete; |
| PositionManager& operator=(PositionManager&& other) = delete; |
| |
| // Validates source and destination frame positions. |
| static void CheckPositions(int64_t dest_frame_count, int64_t* dest_offset_ptr, |
| int64_t source_frame_count, int64_t source_offset, |
| int64_t frac_pos_filter_length, int64_t frac_step_size, |
| uint64_t rate_modulo, uint64_t denominator, |
| uint64_t source_position_modulo_ptr); |
| |
| // Used for debugging purposes only. |
| void Display() const; |
| void DisplayUpdate() const; |
| |
| // Establishes the parameters for this source and dest |
| void SetSourceValues(const void* source_void_ptr, int64_t source_frame_count, |
| Fixed* source_offset_ptr); |
| void SetDestValues(float* dest_ptr, int64_t dest_frame_count, int64_t* dest_offset_ptr); |
| |
| // Specifies the rate parameters. If not called, a unity rate (1:1) is assumed. |
| void SetRateValues(int64_t step_size, uint64_t rate_modulo, uint64_t denominator, |
| uint64_t* source_pos_mod); |
| |
| // Retrieves the pointer to the current source frame (based on source offset). |
| template <typename SourceSampleType> |
| SourceSampleType* CurrentSourceFrame() const { |
| FX_CHECK(frac_source_offset_ >= 0); |
| |
| auto source_ptr = static_cast<SourceSampleType*>(source_void_ptr_); |
| return source_ptr + |
| (frac_source_offset_ >> Fixed::Format::FractionalBits) * source_channel_count_; |
| } |
| |
| // Retrieves the pointer to the current destination frame (based on destination offset). |
| float* CurrentDestFrame() const { return dest_ptr_ + (dest_offset_ * dest_channel_count_); } |
| |
| // Returns true if there is enough remaining source data and destination space to produce another |
| // frame. |
| bool CanFrameBeMixed() const { |
| return (dest_offset_ < dest_frame_count_) && (frac_source_offset_ < frac_source_end_); |
| } |
| |
| // Returns true if there is NOT enough remaining source data to produce another output frame. |
| bool IsSourceConsumed() const { return (frac_source_offset_ >= frac_source_end_); } |
| |
| // Advances one dest frame (and related source, incl modulo); return the new source_offset. |
| int64_t AdvanceFrame() { |
| ++dest_offset_; |
| frac_source_offset_ += frac_step_size_; |
| |
| source_pos_modulo_ += rate_modulo_; |
| if (source_pos_modulo_ >= denominator_) { |
| ++frac_source_offset_; |
| source_pos_modulo_ -= denominator_; |
| } |
| return frac_source_offset_; |
| } |
| |
| // Advances to the end of this source and destination combo, returning the integer source frames |
| // advanced. Skips as much source and destination frames as possible, returning the number of |
| // whole source frames skipped. |
| int64_t AdvanceToEnd(); |
| |
| // Writes back the final offset values. |
| void UpdateOffsets(); |
| |
| // Returns source frame offset. |
| Fixed source_offset() const { return Fixed::FromRaw(frac_source_offset_); } |
| |
| // Returns destination frame offset. |
| int64_t dest_offset() const { return dest_offset_; } |
| |
| private: |
| static void CheckDestPositions(int64_t dest_frame_count, int64_t dest_offset); |
| static void CheckSourcePositions(int64_t source_frame_count, int64_t frac_source_offset, |
| int64_t frac_pos_filter_length); |
| static void CheckRateValues(int64_t frac_step_size, uint64_t rate_modulo, uint64_t denominator, |
| uint64_t source_position_modulo); |
| |
| int32_t source_channel_count_ = 1; |
| int32_t dest_channel_count_ = 1; |
| int64_t frac_positive_length_ = 1; |
| int64_t frac_negative_length_ = kFracOneFrame; |
| |
| void* source_void_ptr_ = nullptr; |
| int64_t source_frame_count_ = 0; |
| Fixed* source_offset_ptr_ = nullptr; |
| int64_t frac_source_offset_ = 0; |
| int64_t frac_source_end_ = 0; |
| |
| float* dest_ptr_ = nullptr; |
| int64_t dest_frame_count_ = 0; |
| int64_t* dest_offset_ptr_ = nullptr; |
| int64_t dest_offset_ = 0; |
| |
| // If `SetRateValues` is never called, we successfully operate at 1:1 (without rate change). |
| int64_t frac_step_size_ = kFracOneFrame; |
| uint64_t rate_modulo_ = 0; |
| uint64_t denominator_ = 1; |
| uint64_t source_pos_modulo_ = 0; // This should always be less than `rate_modulo_` (or both 0). |
| uint64_t* source_pos_modulo_ptr_ = &source_pos_modulo_; |
| }; |
| |
| } // namespace media_audio |
| |
| #endif // SRC_MEDIA_AUDIO_LIB_PROCESSING_POSITION_MANAGER_H_ |